我有两个文件,例如file1="/scratch/abc/osx.xrts"
和file2="/scratch/unzip/abc/osx.xrts"
.
我正在执行diff
命令,忽略行结尾。命令及代码如下:
diff --strip-trailing-cr file1 file2 > /dev/null
if [ $? -eq 0 ]; then
echo "no diff"
elif if [ $? -eq 1 ]; then
echo "there is diff"
else
echo "something is wrong"
fi
观察结果
当我执行此操作时,如果file1
和file2
内容相同,那么我得到的结果为“无差异”,这是正确的。但当内容file1
和file2
内容有一些差异时,问题就来了。在这种情况下,它只是执行diff
命令(如上所述)并打印差异并退出。它根本不会进入 if-else 部分。
我在循环中运行此代码for
(此处未显示),因为我需要比较许多文件。但是我的脚本一旦通过打印差异找到第一对具有差异的文件就会退出,并且根本不会进入 if-else 部分。不知道出了什么问题。任何帮助将不胜感激
我期待的结果
当文件之间存在差异时,它不应该打印差异。相反,它应该转到该部分elif if [ $? -eq 1 ]; then
并打印“存在差异”,然后for
通过比较其他文件继续循环。
答案1
您的代码,纠正了琐碎的印刷错误后,是
(1) diff --strip-trailing-cr "$file1" "$file2" > /dev/null
(2) if [ $? -eq 0 ]; then
(3) echo "no diff"
(4) elif [ $? -eq 1 ]; then
(5) echo "there is diff"
(6) else
(7) echo "something is wrong"
(8) fi
(当然,上图中的行号仅用于说明,而不是脚本的一部分。)这有一个没有其他人指出的微妙错误 - 无论退出状态是什么 diff
,该 echo "something is wrong"
部分都会永远达不到。您可以通过将diff
命令替换为(exit "$1")
,然后传递诸如0
、1
、2
、3
等数字作为参数来轻松测试这一点。
问题是这$?
是一个易失性变量。当然,第 2 行是diff
第 1 行 ( ) 命令的退出状态。但在第 4 行,
$?
是第 2 行 (test) 命令的退出状态[ $? -eq 0 ]
。如果退出状态diff
不是 0 ,那么[ $? -eq 0 ]
测试将设置$?
为 1,所以您将总是收到 there is diff
消息。
有几种方法可以处理这个问题。一种是将退出状态保存diff
在稳定变量中:
diff --strip-trailing-cr "$file1" "$file2" > /dev/null
diff_exit_status=$?
if [ "$diff_exit_status" -eq 0 ]; then
echo "no diff"
elif [ "$diff_exit_status" -eq 1 ]; then
echo "there is diff"
else
echo "something is wrong"
fi
当然,您可以自由使用较短的变量名称。
第二种是使用 case
语句:
diff --strip-trailing-cr "$file1" "$file2" > /dev/null
case "$?" in
(0)
echo "no diff"
;;
(1)
echo "there is diff"
;;
(*)
echo "something is wrong"
esac
答案2
如果file1
和file2
存在且相等,则您的代码片段(如图所示)会生成语法错误:unexpected end of file
。这是因为一个未终止的if
语句,其中 shell 在遇到匹配的fi
.这是由于 haselif if
而不是引起的elif
。除非代码的其余部分存在其他错误,否则这应该可以解决您报告的问题。
此外,您可以直接在一行中检查命令的退出代码,而不是在两个单独的语句中运行命令并检查其退出状态:
if diff --strip-trailing-cr file1 file2 > /dev/null; then
echo "no diff"
elif [ $? -eq 1 ]; then
echo "there is diff"
else
echo "something is wrong"
fi
顺便说一句,在编写 shell 脚本时,用以下命令检查它们确实很有用ShellCheck – shell脚本分析工具。