Bash 如果没有结果,如何停止grep创建空文件
我正在使用Bash 如果没有结果,如何停止grep创建空文件,bash,grep,Bash,Grep,我正在使用grep-v-f file1.txt file2.txt>result.txt对一个文件中不在另一个文件中的行的两个文件的结果进行比较 假设我的文件看起来像 file1.txt alex peter zoey file2.txt alex john peter zoey 所以result.txt应该包含john 这将在Jenkins作业中运行,如果两者之间没有差异,Jenkins最终不喜欢创建一个空的result.txt 我不能只做盲差分/无差分输出,我特别需要知道哪些线不同,如果
grep-v-f file1.txt file2.txt>result.txt对一个文件中不在另一个文件中的行的两个文件的结果进行比较
假设我的文件看起来像
file1.txt
alex
peter
zoey
file2.txt
alex
john
peter
zoey
所以result.txt
应该包含john
这将在Jenkins作业中运行,如果两者之间没有差异,Jenkins最终不喜欢创建一个空的result.txt
我不能只做盲差分/无差分输出,我特别需要知道哪些线不同,如果有的话
如果没有结果,是否有更简洁的方法来运行此命令以不创建文件?您能做一些简单的事情,例如删除空文件吗
解决方案#1:
- grep应该为空输出生成一个非零返回码
- 引用
rm
命令以确保不调用任何别名
- 如果文件不存在,请使用
-f
对任何消息保持沉默(不应该发生,但无论如何也不会影响代码)
解决方案#2:
-s
=>文件存在且大小大于0
-s
=>文件不存在或文件存在且大小为0
'rm'-f
。。。与解决方案#1的解释相同
编辑:尝试有条件地使用quiet选项-q运行命令(当找到一个匹配项时将退出并节省时间)。然后,一旦找到第一个匹配项(意味着文件不同),您将运行相同的命令并将其输出到您的文件中
试试这个:(编辑摘自查尔斯·达菲的评论)
或者使用更少的代码和一行:
grep -qvf file1.txt file2.txt && grep -vf file1.txt file2.txt > output.txt
您可以使用此awk
创建条件差分输出文件:
awk 'NR==FNR{a[$1]; next} !($1 in a){b[$1]} END{
if (length(b) > 0) for (i in b) print i > "result.txt"}' file1.txt file2.txt
输出文件result.txt
仅当由于length(b)>0
检查而有任何输出数据要写入时才会创建。使用grep&&grep
。积极结果:
$ grep -q -m 1 -v -f file1 file2 && grep -v -f file1 file2 > out1
$ cat out1
john
和否定:
$ grep -q -m 1 -v -f file1 file1 && grep -v -f file1 file1 > out2
$ cat out2
cat: out2: No such file or directory
它在第一次匹配后退出第一个grep
,以加快其执行速度,但最坏情况下其执行时间可能是一个grep
运行时间的两倍
另一种方式,另一种awk:
$ awk -v outfile=out3 '
NR==FNR {
a[$0]
next
}
($0 in a==0) {
print $0 > outfile # file is only opened when there is a match
}' file1 file2
$ cat out3
john
该awk无法识别部分匹配。这应该适用于您的情况
out=$(grep -v -f file1.txt file2.txt); [[ -n "$out" ]] && echo "$out" > results.txt
这里的责任人是bash,不是grep。bash中的文件重定向将始终创建该文件,即使该文件没有数据,因此将为空。您必须a)检查文件大小并在文件为空时将其删除;b)为结果创建临时文件并仅在文件不为空时将其移动到位;或者c)运行差异两次,一次确定是否存在任何差异,然后再次将这些差异写入文件(如果存在任何差异)。或者,有没有一种方法可以让Jenkins作业的其余部分不需要result.txt
文件?或者一个临时文件就足以完成您想要完成的任务了吗?为了扩展0x5453所说的内容--在grep foo>out
中,文件out
是在grep
启动之前创建的(否则,grep
将没有可写入其输出的标准输出)。最好使用if!格雷普。。。;然后rm
或grep…|rm
并且不需要显式地检查$?
;检查$?
的代码是脆弱的——添加echo
s以改进日志记录可能会破坏它,并且需要遵循更多的上下文(垂直阅读而不是水平阅读)来理解片段是如何连接的。如果grep-v-f file1 file2.txt;然后…
并且不需要检查$?
。如果您想抑制输出,请使用-q
——否则,测试运行将向stdout发送输出(并且运行的时间超过了获得结果所需的时间,而grep-q
可以在找到单个匹配项后立即退出),这要感谢@CharlesD。所有优点和都已添加到示例中。最好将-q
放在前面(当然不能在-f
和下面的文件名之间)。GNU工具允许在命令行的任何位置使用可选标志,但POSIX标准只要求在前端支持这些标志,因此非GNU平台上的人们可能会看到它在寻找名为-q
@CharlesDuffy的文件。谢谢,我想知道为什么在f之后它就不起作用了。其他人都有完全有效的解决方案,但这是詹金斯内部唯一有效的方法。谢谢好办法。这就是说,我会使用printf“%s\n'$out”
——很多地方echo
行为定义不清或者在shell之间不可移植(例如,请参见ksh
对POSIX进行XSI扩展,并默认扩展反斜杠转义序列)。
$ grep -q -m 1 -v -f file1 file1 && grep -v -f file1 file1 > out2
$ cat out2
cat: out2: No such file or directory
$ awk -v outfile=out3 '
NR==FNR {
a[$0]
next
}
($0 in a==0) {
print $0 > outfile # file is only opened when there is a match
}' file1 file2
$ cat out3
john
out=$(grep -v -f file1.txt file2.txt); [[ -n "$out" ]] && echo "$out" > results.txt