4
votes

I have two text files that I wish to combine in bash so that every line in one file is combined with every file in the other file.

file1.txt

abc123
def346
ghj098

file2.txt

PSYC1001
PSYC1002
PSYC1003

I want to combine them so that line 1 of file1 is added to every line of file2, with a pipe de-limiter | in between them.

e.g.

PSYC1001|abc123
PSYC1002|abc123
PSYC1003|abc123

Then the same for the other lines in file1 so I would end up with

PSYC1001|abc123
PSYC1002|abc123
PSYC1003|abc123
PSYC1001|def346
PSYC1002|def346
PSYC1003|def346
PSYC1001|ghj098
PSYC1002|ghj098
PSYC1003|ghj098<

I've been doing similar simpler text things in bash by copying examples from this site, but I've not found an example that can do this. Would love to hear your suggestion. I know it must be simple but I've not worked it out yet.

4

4 Answers

5
votes

The shortest one - join command:

join -j2 -t'|' -o2.1,1.1 file1 file2
  • -t'|' - input/output field separator
  • -o FORMAT - FORMAT is one or more comma or blank separated specifications, each being FILENUM.FIELD or 0

The output:

PSYC1001|abc123
PSYC1002|abc123
PSYC1003|abc123
PSYC1001|def346
PSYC1002|def346
PSYC1003|def346
PSYC1001|ghj098
PSYC1002|ghj098
PSYC1003|ghj098
4
votes

This awk one-liner should help you:

awk -v OFS="|" 'NR==FNR{a[NR]=$0;c=NR;next}{for(i=1;i<=c;i++){print a[i],$0}}' file2 file1

Test with your data:

kent$  awk -v OFS="|" 'NR==FNR{a[NR]=$0;c=NR;next}{for(i=1;i<=c;i++){print a[i],$0}}' f2 f1
PSYC1001|abc123
PSYC1002|abc123
PSYC1003|abc123
PSYC1001|def346
PSYC1002|def346
PSYC1003|def346
PSYC1001|ghj098
PSYC1002|ghj098
PSYC1003|ghj098 
3
votes

Here are 2 ways to do it in plain bash:

while IFS= read -u3 -r elem1; do 
    while IFS= read -u4 -r elem2; do 
        echo "$elem2|$elem1"
    done 4<file2.txt
done 3<file1.txt
mapfile -t f1 < file1.txt
mapfile -t f2 < file2.txt
for elem1 in "${f1[@]}"; do 
    for elem2 in "${f2[@]}"; do 
        echo "$elem2|$elem1"
    done
done
1
votes

bash only

a1=( $(<f1) )
a2=( $(<f2) )

for i in "${a2[@]}"
do
 for j in "${a1[@]}"
  do
   echo "${j}|${i}"
 done
done