rommedahl
rommedahl

Reputation: 21

Concatenation of columns from the same stream

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

Answers (2)

Nahuel Fouilleul
Nahuel Fouilleul

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

123
123

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

Related Questions