Linux 问题控制脚本流
我对shell脚本还不熟悉,我的脚本看起来不错,但我在控制流程方面遇到了问题。有人能指出我犯了什么愚蠢的错误吗Linux 问题控制脚本流,linux,shell,scripting,Linux,Shell,Scripting,我对shell脚本还不熟悉,我的脚本看起来不错,但我在控制流程方面遇到了问题。有人能指出我犯了什么愚蠢的错误吗 #! /bin/sh echo "Are you sure youx want to delete $1? Answer y or n" read ans echo $ans if $ans = "y"|"Y" then mv $1 /home/parallels/dustbin echo "File $1 has been deleted" else echo "F
#! /bin/sh
echo "Are you sure youx want to delete $1? Answer y or n"
read ans
echo $ans
if $ans = "y"|"Y"
then
mv $1 /home/parallels/dustbin
echo "File $1 has been deleted"
else echo "File $1 has not been deleted"
fi
使您的if条件如下:
if [ "$ans" = "y" -o "$ans" = "Y" ]
您还可以将用户响应转换为任意一种情况,只需检查相应的情况,如
read ans
ans=${ans,,} # make 'ans' lowercase, or use ${ans^^} for making it uppercase
if [ "$ans" = "y" ]
then
....
fi
你的脚本有一些地方不对劲。有些是严重的,有些则不那么严重 第一,严重的问题 正如古鲁所建议的,您需要使用方括号来包围您的
if
条件。这是因为如果
只测试条件的输出,它不会执行实际的字符串比较。传统上,一个名为/bin/test
的程序(也称为/bin/[
的程序)会处理这个问题。现在,这个功能内置在shell中,但/bin/sh
仍然像是一个单独的程序一样运行
事实上,如果你不使用方括号来表示你的病情,你可以用if
做一些有趣的事情。例如,如果grep-q'RE'/path/to/file;那么是很常见的。grep-q
命令不发出输出,只返回一个由if
检测到的“成功”或“失败”
第二个严重问题是,您正在回显一个状态,该状态可能是真的,也可能不是真的。我认为这是一个严重问题,因为……好吧,日志消息不应该做出错误的声明。如果$1
中的文件权限错误,或者文件名包含空格,则mv
命令将失败,但消息将失败声称它没有。稍后会详细介绍
其次是不太严重的问题
这些都是风格和优化方面的东西
首先,在大多数平台上,read
包含一个-p
选项,用于指定提示。使用该选项,您不需要包含echo
命令
其次,如果
结构正在包装,缩进会使您很难看到结构是什么。这在这么小的程序中不是一个大问题,但随着您的成长,您确实希望遵循一致的标准
第三,如果您使用case
语句而不是if
语句,您可能会在这样的选择题中获得更大的灵活性
在所有这些之后,下面是我如何编写这个脚本:
#!/bin/sh
if [ "$1" = "-y" ]; then
ans=y
shift
elif [ -t 0 ]; then
read -p "Are you sure you want to delete '$1' (y/N) ? " ans
fi
case "$ans" in
Y*|y*)
retval=0
if [ -z "$1" ]; then
retval=64
echo "ERROR: you didn't specify a filename." >&2
if [ ! -f "$1" ]; then
retval=66
echo "ERROR: file '$1' not found!" >&2
elif mv "$1" /home/parallels/dustbin/; then
echo "File '$1' has been deleted" >&2
else
retval=$?
echo "ERROR: file '$1' could not be deleted!" >&2
fi
;;
*)
echo "ABORT: file '$1' has not been deleted" >&2
retval=4
;;
esac
exit $retval
除了上面提到的内容外,此代码段中还有一些内容:
[“$1”=“-y”]
-如果用户指定了一个-y
选项,那么我们的行为就好像问题的答案是“是”
[-t0]
-这测试我们是否在交互终端上。如果在交互终端上,那么用阅读提问是有意义的
Y*| Y*)
-在case语句中,它匹配以大写或小写“Y”开头的任何字符串。因此,有效的肯定回答将是“Y”、“yes”、“yellow”等
[!-f“$1”]
-此测试文件是否存在。您可以man test
或man sh
查看shell中可用的各种测试。(-f
可能不是最适合您的。)
&2
-在一行的末尾,将其输出发送到“标准错误”而不是“标准输出”。这改变了管道、cron等处理输出的方式。错误和日志数据通常发送到stderr,以便stdout可以专用于程序的实际输出
mv“$1”…
-文件名用引号括起来。如果文件名中有空格等特殊字符,这将为您提供保护
$retval
-此项的值来自对中最近项的最佳猜测
retval=$?
-这是最近执行的命令的退出状态。在这种情况下,这意味着我们将mv
的退出状态分配给变量$retval
,因此如果mv
失败,整个脚本将报告失败的原因,只要mv
下面是包含错误处理的完美代码
#!/bin/sh
echo "Are you sure you want to delete $1? Answer y or n"
read ans
echo $ans
if [ $ans == "y" ] || [ $ans == "Y" ]
then
if [ -f $1 ]
then
mv $1 /home/parallels/dustbin
echo "File $1 has been deleted"
else
echo " File $1 is not found"
fi
else
echo "File $1 has not been deleted"
fi
感谢您快速而有用的回答!欢迎您。如果解决方案对您有效,请接受答案。如果有多个答案对您有效,请接受最适合您问题的答案…我唯一的问题是,如果mv
失败,是否还需要从脚本返回错误代码(这目前被echo错误隐藏。
返回ok)@GermanGarcia-是的,这可能是个好主意,特别是如果脚本是精心编制的,可以由其他脚本包装。我已更新了答案,以包含更多“学习”。-)很好的教学答案。干杯。这种转换成小写的方法只在bash中有效。OP的脚本运行/bin/sh
-我们不知道bash是否也可用,但即使可用,您的答案可能也应该将bash指定为需求,因为bash在作为sh
调用时使用POSIX行为。