Home > OS >  How to concatenate and loop through two columns using just Bash variables, i.e. without temporary fi
How to concatenate and loop through two columns using just Bash variables, i.e. without temporary fi

Time:08-17

I have two Bash variables that contain 2 columns of data. I'd like concatenate them to create two larger columns, and then use this outcome to loop in the resulting rows, having each column read in respective temporal variables.

I'll explain what I need with minimal working example. Let's think I have a tmp file with the following sample content:

for i in `seq 1 10`; do echo foo $i; done > tmp 
for i in `seq 1 10`; do echo bar $i; done >> tmp
for i in `seq 1 10`; do echo baz $i; done >> tmp

What I need is effectively equivalent to the following code that relies in external temporary files:

grep foo tmp > file1
grep bar tmp > file2

cat file1 file2 > file_tmp

while read word number
do
  if [ $word = "foo" ]
    then
    echo word $word number $number
  fi  
done < file_tmp


rm file1 file2 file_tmp

My question then is: how can I to achieve this result, i.e. concatenating the two columns and then looping across rows, without having to write out the temporary files file1, file2 and file_tmp?

CodePudding user response:

while
    read -u3 foo1 foo2 &&
    read -u4 bar1 bar2
do
    echo "$foo1 $foo2 - $bar1 $bar2"
done 3< <(grep ^foo tmp) 4< <(grep ^bar tmp)

The code above is a kind of zip function. Note that it doesn't address ensuring that the ordering of the two sequences is correct.


It's not clear why your code in the question creates and then ignores bar lines. If you are doing that, the code is even simpler:

while read word number; do
    echo "word $word number $number"
done < <(grep ^foo tmp)

CodePudding user response:

I may have misunderstood, but if you want to do this without temp files, perhaps this would work for your use-case:

# Gather the output from the 3 'seq' commands and pipe into AWK
{ 
  for i in $(seq 1 10); do echo foo "$i"; done ;
  for i in $(seq 1 10); do echo bar "$i"; done ;
  for i in $(seq 1 10); do echo baz "$i"; done ; 
} |\
awk '{
  if ($1=="foo" || $1=="bar") {a[NR]=$1; b[NR]=$2}} 
  END{for (i in a) {print "word " a[i] " number " b[i]}
}'

# For the AWK command: if a line contains "foo" or "bar",
# create an array "a" for the word, indexed using the row number ("NR")
# and an array "b" for the number, indexed using the row number ("NR")
# Then print the arrays with the words "word" and "number" and the correct spacing

Result:

word foo number 1
word foo number 2
word foo number 3
word foo number 4
word foo number 5
word foo number 6
word foo number 7
word foo number 8
word foo number 9
word foo number 10
word bar number 1
word bar number 2
word bar number 3
word bar number 4
word bar number 5
word bar number 6
word bar number 7
word bar number 8
word bar number 9
word bar number 10

CodePudding user response:

You use awk to achieve this.

awk '{if($1=="foo") {print "word "$1" number "$2}}' file_tmp

CodePudding user response:

you mean like this ??

paste <( jot - 1 9 2 ) <( jot - 2 10 2 )
1   2
3   4
5   6
7   8
9   10
  • Related