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:
- Bash's
read
can take input from a file descriptor other than stdin. - Bash has process substitution
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