Anshuman Bhoi
Anshuman Bhoi

Reputation: 57

Bash - Transpose a single field keeping the rest same and repeat it across

I have a file with pipe separated fields. eg.

1,2,3|xyz|abc

I need the output in below format:

1|xyz|abc
2|xyz|abc
3|xyz|abc

I have a working code in bash:

while read i
do
    f1=`echo $i | cut -d'|' -f1`
    f2=`echo $i | cut -d'|' -f2-`
    echo $f1 | tr ',' '\n' | sed "s:$:|$f2:" >> output.txt
done < pipe_delimited_file.txt

Can anyone suggest a way to achieve this witout using loop. The file contains a large number of records.

Upvotes: 2

Views: 56

Answers (2)

glenn jackman
glenn jackman

Reputation: 246877

Perl may be a bit faster than awk:

perl -F'[|]' -ane 'for $n (split /,/, $F[0]) {$F[0] = $n; print join "|", @F}' file

bash is very slow, but here's a quicker way to use it. This uses plain bash without calling any external programs:

(                                      # in a subshell:
    IFS=,                              # use comma as field separator
    set -f                             # turn off filename generation
    while IFS='|' read -r f1 rest; do  # temporarily using pipe as field separator,
                                       #   read  first field  and  rest of line
        for word in $f1; do            # iterate over comma-separated words
            echo "$word|$rest"
        done
    done
) < file

Upvotes: 0

simon3270
simon3270

Reputation: 732

Uses a loop, but it's inside awk, so very fast:

awk -F\| 'BEGIN{OFS="|"}{n = split($1, a, ","); $1=""; for(i=1; i<=n; i++) {print a[i] $0}}' pipe_delimited_file.txt

Upvotes: 4

Related Questions