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