Alex
Alex

Reputation: 2805

how to stop grep creating empty file if no results

I'm comparing the results of two files for lines in one that are not in the other using grep -v -f file1.txt file2.txt > result.txt

Let's say my files look like;

file1.txt

alex
peter
zoey

file2.txt

alex
john
peter
zoey

So result.txt should contain john

This is to be run inside a Jenkins job, and jenkins ends up not happy with creating an empty result.txt if there are no differences between the two.

I can't just do a blind diff/no diff output, I specifically need to know which lines differ if there are any.

Is there a neater way to run this command to not create a file if there are no results?

Upvotes: 5

Views: 3235

Answers (5)

9Breaker
9Breaker

Reputation: 724

EDIT: Try conditionally running the command with the quiet option -q (which will exit when one match is found and save time). Then once the first match is found (meaning the files are different), you will run the same command and output it to your file.

Try this: (EDIT taken from Charles Duffy's comment)

#!/usr/bin/env bash

if grep -qvf file1.txt file2.txt 
then
   grep -vf file1.txt file2.txt > output.txt
   echo "Differences exist. File output.txt created." 
else
   echo "No difference between the files detected"
fi

Or with less code and one line:

grep -qvf file1.txt file2.txt && grep -vf file1.txt file2.txt > output.txt

Upvotes: 5

Diego Torres Milano
Diego Torres Milano

Reputation: 69198

This should work for your case

out=$(grep -v -f file1.txt file2.txt); [[ -n "$out" ]] && echo "$out" > results.txt

Upvotes: 3

James Brown
James Brown

Reputation: 37404

Using grep && grep. Positive result:

$ grep -q -m 1 -v -f file1 file2 && grep -v -f file1 file2 > out1 
$ cat out1
john

and negative:

$ grep -q -m 1 -v -f file1 file1 && grep -v -f file1 file1 > out2
$ cat out2
cat: out2: No such file or directory

It exits the first grep after the first match to quicken its execution but still its execution time at the worst could be twice the runtime of one grep.

Another way, another 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

That awk won't recognize partial matches.

Upvotes: 0

anubhava
anubhava

Reputation: 785058

You can use this awk for conditional differential output file creation:

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

Output file result.txt will only be created when there is any output data to be written due to length(b) > 0 check.

Upvotes: 3

markp-fuso
markp-fuso

Reputation: 34174

Could you do something as simple as removing the file if it's empty?

Solution #1:

grep -v -f file1.txt file2.txt > result.txt
[[ $? -ne 0 ]] && 'rm' -f result.txt
  • grep should generate a non-zero return code for an empty output
  • quote the rm command to ensure not calling any aliases
  • use the -f to keep silent any messages should the file not exist (shouldn't happen, but doesn't hurt to code for this anyway)

Solution #2:

grep -v -f file1.txt file2.txt > result.txt
[[ ! -s result.txt ]] && 'rm' -f result.txt
  • -s => file exists and is greater than 0 in size
  • ! -s => file doesn't exist or file exists and is 0 in size
  • 'rm' -f ... same explanation as for solution #1

Upvotes: 5

Related Questions