我有一个 shell 脚本,我想在其中验证文件的内容。
预期的内容应该有一个特定的第一行,例如^MYFIRSTROW
,和不能为空。
所以我使用 GNU 编写了这个检查sed
:
#!/bin/bash
# "1q1": return 1 on input line 1. Only reached if the pattern did not match.
if sed -rn '/^MYFIRSTROW/q0; 1q1' myfile; then
# ...
fi
但我在空输入上进行了测试,然后sed
返回 0 而不是 1:
echo -ne '' | sed -rn '/^MYFIRSTROW/q0; 1q1'; echo $?
# 0
另外,在这种情况下我没有找到使用地址“0”的方法。
有没有一种方法可以在 GNU sed 中用一个命令来实现它?
注意:替代解决方案
我主要想回答是否可以在空输入上执行 sed 命令以及如何执行,但欢迎对我的 shell 脚本提出优雅的建议:
我很慢,但我刚刚意识到这
if [ -s "myfile" ] && sed ...
可以完成工作。我可以想象使用
while read < myfile
但似乎很麻烦的解决方案。我在 中遇到了相反的问题
awk
,其中 END 块始终被执行,因此此代码始终返回 1:awk 'NR==1 && /^MYPATTERN/ {exit 0}END{exit 1}' myfile
PS:抱歉,我的问题可能看起来太像代码高尔夫请求,但我只是想在我的脚本中进行简洁高效的文件内容检查。
答案1
主要答案是:否。sed
对每一行执行其脚本,因此如果没有行,则无法执行任何命令。
解决方法:让你的 shell 立即添加一行:
sed -n '/^MYPATTERN/q;$q1;2q2' <(echo) yourfile
假装<(echo)
是一个只有一个空行的文件,因此sed
将始终执行它的脚本。如果yourfile
为空,则第一行也是最后一行,因此$q1
将以状态 1 退出。
否则脚本将在 的第一行执行yourfile
。如果匹配,则退出并返回状态码 0。
如果不匹配,则sed
存在,状态为 2。请注意,添加的行使文件的第一行显示为第 2 行sed
。
感谢 Stéphane Chazelas 提示如何在不支持 ksh 样式进程替换的情况下为 shell 实现相同的功能:
echo|sed -n '/^MYPATTERN/q;$q1;2q2' - yourfile
as-
参数代表 stdin,它是从 管道传输的空行echo
。
答案2
使用 AWK,您可以设置一个变量来告诉END
块要设置哪个退出代码。在这里,滥用了ok
如果没有明确分配则为零的事实。 (或者,添加BEGIN { ok=0 }
明确的内容。)
awk 'NR==1 && /^MYPATTERN/ {ok=1; exit} NR==2 {exit} END {exit !ok}' myfile
这是故意的,而且很可能是打高尔夫球的。因为我们只在第一行寻找模式。
我不知道如何在 sed 中以简单的方式做到这一点。尽管您可以颠倒过来,如果MYPATTERN
看到则以1 退出,并依赖于空文件以 0 退出。然后你需要反转周围的感觉if
:
if ! sed -Ene '/^MYPATTERN/q1; 1q0' myfile; then
echo "MYPATTERN seen..."
fi
尽管这会转到if
(和 print MYPATTERN seen...
) 的主分支,即使 sed 返回实际错误,例如无法读取myfile
.