您的脚本有一些问题。有些是严重的,有些则不那么严重。
一是问题严重。
正如大师建议的那样,您需要使用方括号来包围您的if
状况。这是因为if
只测试条件的输出,它不执行实际的字符串比较。传统上,一个名为 的程序(/bin/test
也称为/bin/[
)负责处理该问题。如今,该功能已内置到 shell 中,但/bin/sh
仍然表现得好像它是一个单独的程序。
事实上,if
当你不使用方括号来表示你的情况时,你可以做一些有趣的事情。例如,if grep -q 'RE' /path/to/file; then
很常见。该grep -q
命令不发出任何输出,而只是返回由if
.
第二个严重的问题是你正在呼应一个可能是也可能不是真的状态。我称这是一个严重的问题,因为......好吧,日志消息根本不应该做出虚假声明。如果 中的文件的权限错误$1
,或者文件名包含空格,则您的mv
命令将失败,但消息将声称它没有。稍后再谈。
接下来,不太严重的问题。
这些主要是样式和优化的东西。
首先,read
在大多数平台上都包含一个-p
允许您指定提示的选项。使用它,您不需要包含echo
命令。
其次,您的缩进使得很难看到if
构造正在包装什么。在这么小的程序中,这不是一个大问题,但是随着您的成长,您真的希望遵循一致的标准。
第三,如果您使用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
选项,那么我们的行为就好像问题是用“是”回答的。
[ -t 0 ]
- 这测试我们是否在交互式终端上。如果我们是,那么用 提问是有意义的read
。
Y*|y*)
- 在 case 语句中,这匹配任何以大写或小写“y”开头的字符串。因此,有效的肯定回答将是“Y”、“yes”、“yellow”等。
[ ! -f "$1" ]
- 这将测试文件是否存在。您可以man test
或man sh
查看 shell 中可用的各种测试。(-f
可能不是最适合你的。)
>&2
- 在一行的末尾,将其输出发送到“标准错误”而不是“标准输出”。这改变了管道、cron 等处理输出的方式。错误和日志数据通常被发送到 stderr,因此 stdout 可以专用于程序的实际输出。
mv "$1" ...
- 文件名用引号括起来。这可以保护您,以防文件名中包含空格等特殊字符。
$retval
- 此值来自对 中最接近的项目的最佳猜测man sysexits
。
retval=$?
- 这是最近执行的命令的退出状态。在这种情况下,这意味着我们将mv
的退出状态分配给变量$retval
,因此如果mv
失败,则整个脚本会报告失败的原因,就目前mv
而言。