1
File1:
X
X
P
X
N
X
Q
File2:
P 1
N 5
Q 0

Desired output:
X 0
X 0 
P 1
X 0
N 5
X 0
Q 0

I have tried a lot of ways using merge command on bash. I couldn't make it work.

  • Note that merge is for 3-way merges, which is a very different thing from what you want. What you want looks more like a "left join" in database terms, except you also need a default value. For left joins, see e.g. here. – dirkt May 3 at 10:41
3

You can do this in Awk very easily!

awk 'FNR==NR{ hash[$1]=$2; next}{ if ($0 in hash) $2 = hash[$1]; else  $2 = "0" }1' file2 file1

Awk works by processing input lines one at a time. And there are special clauses which Awk provides, BEGIN{} and END{} which encloses actions to be run before and after the processing of the file. Each line in the file is split based on the value of special variable FS (default one or more whitespaces) and those individual fields can be accessed from $1,$2..$NF

So the part FNR==NR is meant to process the first file argument provided in the command, because FNR keeps track of the line numbers for the both the files combined and NR for only the current file. So for each $1 in the first file, the values are hashed into the array called hash and then when the next file processing happens, the part $0 in hash will map those lines in the file1 where the hashed indices from file2 are present. For such mapped lines, we print their equivalent values and for non-mapped lines we print 0.

The {..}1 is a short-hand representation to do {..; print} to basically reconstruct/print the entire line based on the modification to individual fields or to any of the said special variables.

See more of Built-in Variables That Control awk

  • 1
    or using ternary operator instead of if-else statement awk 'NR==FNR { hash [$1]=$2 ; next} { print $1, !hash[$1]?"0":hash[$1] }' file2 file1 – αғsнιη May 2 at 18:51
0

You can do this with sed, however, the Gnu version of the editor can make the regex less noisy.

Basic idea is to read the File2 first and store it in the hold space, with its lines being newline separated.

Then we read File1 and append the lines of File2 from hold onto the just-read line of File1. If we are able to detect the presence of File1 line in hold space, its a go, and we print File2 line as is by pruning the pattern space of other stuff.

Otherwise, we print File1 line with a 0 appended.

$ sed -Ee '
    / /{H;d;}
    G
    s/^(\S+)\n.*\n(\1 \S+)(\n.*)?$/\2/;t
    s/\n.*/ 0/
' File2 File1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.