Using perl (with extra linefeeds for readability):
$ perl -MFile::Basename -F'\t' -le '
$f = fileparse($ARGV, qw(.txt)) if $. == 1;
if ($F[2] =~ /^(likely_)?patho$/) {
push @{ $files{$f} }, $F[1]
};
close(ARGV) if eof; # close each input file and reset the line counter $. at eof
END {
foreach (sort keys %files) {
print "$_\t", join(";",@{ $files{$_} })
}
}' A.txt B.txt
A toto;titi
B lolo
-MFile::Basename
tells perl to load the File::Basename module. This is a core perl module and is included with perl.
-F
sets the field separator (tab) and also enables both perl's -a
auto-split mode (splits each input line into an array called @F
, similar to awk), and perl's -n
option to iterate over its input (behaves similarly to both sed -n
and awk
).
-l
enables automatic processing of line-endings (\n
by default). In short, it removes newline characters from the end of each input line (using perl's chomp()
function) and adds them to the end of every print
statement.
All perl command-line options are documented in man perlrun
.
The script iterates over each input line and, whenever it finds a match in the third field ($F[2]
- perl array indices start from zero) it adds the second field to a Hash-of-Arrays (HoA) called %files
. This is a hash (associative array) where the key is the base filename and the value is an array of 2nd-field strings. See the man pages for perldata
, perllol
, and perldsc
for more information about perl data structures.
When all the input has been read and processed, it output the data in the requested format, sorted by filename.
NOTE: The ... if $. == 1;
in conjunction with the close(ARGV) if eof
line ensures that the base filename is only extracted on the first line of each new file. This isn't required, just a minor optimisation that would only be beneficial if you have very large input files. If you prefer a slightly shorter one-liner or if performance isn't an issue, delete the close(ARGV) ...
line and the if $. == 1
conditional.