0

I'm using grep -f and would like to make grep print also lines in file 1 that are missing in file 2:

file1:

hello
my
name
is
bernardo

file 2:

hello 1
my 2
name 3
is 4

ideal output:

hello 1
my 2
name 3
is 4
bernardo
biotech
  • 697
  • 1
  • 7
  • 17

2 Answers2

2

This will print the lines in file2 that are not in file1:

fgrep -F -x -v -f file1 file2

The -F means to treat the input as fixed strings rather than patterns, the -x means to match the whole line, the -v means to print lines that don't match rather than those that do match, and -f file1 uses file1 as a list of patterns.

Your question is kind of unclear but I'm guessing that you want all of the lines that appear in one or the other file but not both. There's several ways to do that. One is to do two greps:

fgrep -F -x -v -f file2 file1; fgrep -F -x -v -f file1 file2

Another, if the order of the lines in the output doesn't matter, is to sort them and use comm:

sort file1 -o sortfile1
sort file2 -o sortfile2
comm -3 sortfile1 sortfile2
  • As I understand it, OP wants to print lines from `file2` that are matches for lines in `file1` *and* lines from `file1` that have no matches in `file2`. – mcmlxxxvi Jun 01 '16 at 15:47
0
grep -f file1 file2 && grep -o -f file1 file2 | sed s'/^\(.*\)$/-e "\1"/g' | tr '\n' ' ' | xargs grep -v file1

What this does is print all matches from file2 by patterns in file1, and after that print all lines from file1 that do not match files in file2. The second part is done as follows:

  • grep -o -f file1 file2 returns matches between file and file2, but only the matching parts of the lines;
  • sed s'/^\(.*\)$/-e "\1"/g' | "\1"/g' | tr '\n' ' ' prefixes those matching parts with -e, encases them in double quotes, and replaces newlines printed by the grep -f command with spaces. This builds a string of the form -e "[pattern1]" -e "[pattern2]" ..., which is what grep uses for multiple patterns matching. The quotes (hopefully) ensure that spaces in patterns will not be a problem;
  • xargs grep -v file1 builds and executes the command grep -v file1 [whatever was piped to xargs]. The result is all lines from file1 that have not match in the output of the first command (and, thus, in file2).

I'm not completely sure this solves your problem since non-matching lines from file1 are printed at the end (by far the easiest option), and you do not say where you want them. It probably could be done more elegantly, too.

Here's a sample output:

sh-4.3$ cat file1
hello
my
name
is
bernardo

sh-4.3$ cat file2
hello 1
my 2
name 3
is 4

sh-4.3$ grep -f file1 file2 && grep -o -f file1 file2 | sed s'/^\(.*\)$/-e "\1"/g' | tr '\n' ' ' | xargs grep -v file1
hello 1
my 2
name 3
is 4
bernardo
mcmlxxxvi
  • 1,358
  • 1
  • 11
  • 21