-4

I have a file looks like below as a sample:

B01 112178282 A01 112178282
A05 44887670 A01 44887670
B01 114451441 A01 114451441
B10 8364597 A01 8364597
B01 123453906 A01 123453906
A05 9155966 A01 9155966
A05 86420950 A01 86420950
A10 75684694 A01 75684694
A04 71261964 A01 71261964
B01 1262441 A01 1262441
B01 471272 A01 471272
B01 17007 A01 17007
A04 115637044 A01 115637044
A07 9376758 A01 9376758

I want to have two separate output files

  1. When num val in col1 == num val in col3
  2. second output file When num val in col 1 != num val in col 3

For an example, col1 is B01 and col3 A01, here in both columns the numeric part is same 01. Now, all such conditions should be listed in file1.

If col1 is A05 and col3 is A01, here in both columns the numeric part is different 07 != 01, then these should be listed in another file2

  • 2
    A follow up to unix.stackexchange.com/q/382491/203203? Or is it an assignment? What did you try? – xhienne Jul 29 '17 at 0:50
  • 1
    The only new requirement is to write the result to two files. Is that all ?. Then: What have you tried? What is exactly your problem? – Arrow Jul 29 '17 at 1:56
1
awk 'substr($1,2)==substr($3,2) { print $0 > "file1" } substr($1,2) != substr($3,2) { print $0 > "file2" }' masterfile

With masterfile containing the original data and using the substr function of awk, we ignore the first letter of the first and third space delimited fields leaving us with the numbers to compare. We then perform conditional checks on these numbers placing them in specific files (file1 and file2) accordingly.

  • good point to using substr, also you could use if/else to avoid adding another condition substr($1,2) != substr($3,2) or using "Ternary operator" as in my answer , + by default awk prints whole line no need to have $0 with print – αғsнιη Jul 30 '17 at 6:26
  • Good points but not very understandable for novices. It's good to give the poster a variety of solution strategies though. – Raman Sailopal Jul 30 '17 at 11:02
1

Using awk will produce two files; Those lines which 1st&3rd columns' numeric parts were same will goes in a separate file and those lines where these columns were different into the another file.

awk -F"[A B]" '{
    print >(($2==$5)?"matches.txt":"non_matches.txt")
}' infile.txt

This will set awk's field separator to sets of A, B or Space characters, then do compare, if numeric parts were same then current line will write to "matches.txt" file, else it will write to "non_matches.txt" file.

0
perl -alMFatal=open -pe '
   BEGIN{ unlink, open *{+uc}, ">>$_" for qw/file1.log file2.log/; }
   select $F[0] =~ s/^\D*//r eq $F[2] =~ s/^\D*//r ? *{"FILE1.LOG"} : *{"FILE2.LOG"};
' sample.txt

Explanation

  • Perl options:
    • -a will split the line into fields based on whitespace and those fields are available via $F[0] $F[1] ...
    • -l will set the RS to newline and ORS to newline.
    • -M will load the module Fatal.pm and include a function open from it's namespace. This means that any errors in opening a file in the main code shall die.
    • -p will read the sample.txt file line-by-line and auto-printing of lines is enabled after all transformations have been applied to it.
  • The BEGIN block shall remove any existing file1.log and file2.log and open filehandles in an append mode to files.
  • select command chooses the filehandle on which to print the current line.
    • $F[0] =~ s/^\D*//r shall strip any leading nondigits in the first field (this assumes all digits are placed at the end of the field).
    • We perform a similar operation on the 3rd field ($F[2]) and then compare these results in a string format (and NOT in numeric, since 001 = 1 in numeric). When the strings match we select the filehandle *FILE1.LOG which means the current line is printed here, due to the -p option. OTW, the filehandle *FILE2.LOG is made the default handle and the -p option makes Perl prints the current line here.

We can do the same using sed tool as well as shown: (Assuming GNU sed)

sed -Ee '
   h;s/\S+/\n&\n/3
   /^[^0-9[:blank:]]*([0-9]+).*\n(.*[^0-9])?\1\n/{
      g
      s/^//w file1.log
      d
   }
   g
' < sample.txt > file2.log

  • In the first step we enclose the third field via markers.
  • Then we perform the comparison of the digits in the trailing portion of the first field to match with the digits in the trailing portion of the third field.
  • On match, we recall the hold space where we had stored the current line sans the markers and append it in file1.log file.
  • On no match, we recall the hold space and let it go to stdout where it is stored in the file2.log file by the shell.
0

Using GNU sed with an editing script (adjust the path and name of GNU sed on the first line to match your system):

#!/usr/bin/sed -nrf

/^[A-Z]([0-9]+) [0-9]+ [A-Z]\1 [0-9]+$/{
    w match.txt
    b
}
w nonmatch.txt

Running this on the example file will produce the two result files match.txt and nonmatch.txt:

$ chmod +x script.sed

$ ./script.sed file.in

$ cat match.txt
B01 112178282 A01 112178282
B01 114451441 A01 114451441
B01 123453906 A01 123453906
B01 1262441 A01 1262441
B01 471272 A01 471272
B01 17007 A01 17007

$ cat nonmatch.txt
A05 44887670 A01 44887670
B10 8364597 A01 8364597
A05 9155966 A01 9155966
A05 86420950 A01 86420950
A10 75684694 A01 75684694
A04 71261964 A01 71261964
A04 115637044 A01 115637044
A07 9376758 A01 9376758

The script basically tries to match a particular regular expression on each line. The expression matches if the two numbers in column 1 and 3 are identical (I'm using a back reference here to do this, which is why BSD sed won't be able to run this script).

If the two numbers are equal, the line gets written to match.txt and the script branches to the start and continues with the next line of input.

If the line does not match the regular expression, it gets written to nonmatch.txt.

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.