Reputation: 21
Related to my previous question.
From a stream with columns.
cat file
a d 1 4 b e 2 5 c f 3 6
How are the columns/fields concatenated into columns, e.g. like this.
a 1 b 2 c 3 d 4 e 5 f 6
I have tried to use my preferred command cut
as shown below, but with only the output from the first cut
command.
cat file | ( cut -f1,3; cut -f2,4; )
or
cat file | { cut -f1,3; cut -f2,4; }
a 1 b 2 c 3
Upvotes: 0
Views: 62
Reputation: 19315
cat file |
= useless use of cat ; one can use < file
instead
cut -f1,3 <file
cut -f2,4 <file
but from performance point of view, it launches 2 processes, opens file twice and reads twice, this can be done with builtins
str=
while read k1 k2 v1 v2; do
echo "$k1"$'\t'"$v1"
str=$str$k2$'\t'$v2$'\n'
done < file
echo -n "$str"
EDIT: because of poor performance of read, for big files it would be better to use a text processing tool like awk, sed or more complete perl, here a one-liner for example:
perl -a -pe '$_="$F[0]\t$F[2]\n";$s.="$F[1]\t$F[3]\n";END{print$s}' <file
Upvotes: 0
Reputation: 11216
Using awk you could do
awk '{for(i=1;i<=NF-2;i++)a[$i]=$(i+2)}END{for(i in a)print i,a[i]}' test
a 1
b 2
c 3
d 4
e 5
f 6
So save keys into an associative array and assign the field after next to it.
Note this will not preserve order though, it is just coincidence if it does.
Also your original
cat file | ( cut -f1,3; cut -f2,4; )
Does not work because the first cut consumes the stream and it never gets to the second.
You could do something like
<file tee >(cut -f2,4) >(cut -f1,3) >/dev/null
Which would send the stream to both commands.
Upvotes: 2