I have the below data as input:
A 1,2
B 3,2,5
C 6,7
D 1,3,5,8
How can I get the below output using AWK?
A 1
A 2
B 3
B 2
B 5
C 6
C 7
D 1
D 3
D 5
D 8
$ awk -F '[ ,]' '{ for (i = 2; i <= NF; ++i) print $1, $i }' file
A 1
A 2
B 3
B 2
B 5
C 6
C 7
D 1
D 3
D 5
D 8
This treats the lines as consisting of fields delimited by either spaces or commas. For each line, the awk
program iterates over the second field onwards to the end of the line. For each field, it outputs the first field on the line together with the current field.
awk '{gsub(/,/, "\n" $1 " "); print}' file
In this solution we are just replacing every ",
" by "\n$1 "
Using sed
with the extended regex engine enabled we can do as shown:
$ sed -re '
s/^((\S+\s+)[^,]+),/\1\n\2/
P;D
' file
With Perl
we can do as :
$ perl -F'\s+|,' -lane '
print join $", splice @F, 0, 2, $F[0] while @F > 1;
' file
Split the current record on either a run of whitespace or comma and store in zero indexed array @F
.
Splice the first two elements of the array and join them with single space $"
and print them. Also at the same time replace the two removed elements with the first. Repeat this process till only a single element remains.
If sed
is an option, you could do:
sed -E ':a s/^([^ ]* )(.*),([^,]*$)/\1\2\n\1\3/; ta' infile
considering below input:
B 2,3,5,6
C 6,7
D 1,3,5,8
([^ ]* )
capture first column (assuming space is a delimiter); it will capture B
(B followed by a space).(.*),
capture everything until last comma seen; it will capture 2,3,5
This ([^,]*$)
captures the rest of the line (ie: last field after last comma every time); it will capture 6
so \1\2\n\1\3
would result as below at first loop-run for first line:
sed -E ':a s/^([^ ]* )(.*),([^,]*$)/\1\2\n\1\3/;q ;ta' infile
B 2,3,5
B 6
next loop-run it would result as below:
B 2,3
B 5
B 6
finally in last loop-run for first line will output as below:
sed -E ':a s/^([^ ]* )(.*),([^,]*$)/\1\2\n\1\3/ ;ta ;q' infile
B 2
B 3
B 5
B 6
now read next line and do the same process until all lines proceed and finished.