2

I have the following structure of text lines:

3923 001    L05 LV,L05 RM
3923 002    L12 RA,L12 LA
3923 003    I06 ALL
3923 004    G04 RV,Z09 ALL

but i would need this:

3923 001    L05 LV
3923 001    L05 RM
3923 002    L12 RA
3923 002    L12 LA
3923 003    I06 ALL
3923 004    G04 RV
3923 004    Z09 ALL

Is this possible with a regex ?

Basicly I need every line copyd the amount of times it contains a "," and then made unique starting from the 10nth character; if i could get the first part done, so just a copy of every line x the amount of comma's, i could clean the rest manually

3
  • You can't give assignments to ppl over here.So,what have you tried so far?
    – Thushi
    Jul 16 '15 at 8:46
  • i tried using: find: , replace by; ^.......... [] ; i'm a total noob at this; i'm trying to learn, sorry if i posted this wrong. :(
    – Randy V
    Jul 16 '15 at 8:50
  • 1
    No worries....Just post it even if it is wrong.
    – Thushi
    Jul 16 '15 at 8:53
7

Given the format of your example this should work for any number of comma separated strings after the initial large space(if it's a tab just change the spaces in the second s/// to \t

sed ':;h;s/,.*//;p;x;s/    [^,]*,/    /;t;d' file

3923 001    L05 LV
3923 001    L05 RM
3923 002    L12 RA
3923 002    L12 LA
3923 003    I06 ALL
3923 004    G04 RV
3923 004    Z09 ALL

If you want tabs then

if you want to write the tab as \t, you can give it to Bash using $'' quotes: sed $':;h;s/,.*//;p;x;s/\t[^,]*,/ /;t;d'. Or just insert a literal tab (for bash, you need to type control-v to enter it literally). .

Toby Speight
3
  • Upvoted.Works with multiple "," too.
    – Thushi
    Jul 16 '15 at 9:33
  • This will obviously be correct; but me being such a noob, i'm not getting it to work, the large space is a tab, so the code becomes ? sed ':;h;s/,.*//;p;x;s/\t[^,]*,/ /;t;d' file ?
    – Randy V
    Jul 16 '15 at 10:04
  • @Randy - if you want to write the tab as \t, you can give it to Bash using $'' quotes: sed $':;h;s/,.*//;p;x;s/\t[^,]*,/ /;t;d'. Or just insert a literal tab (for bash, you need to type control-v to enter it literally). Jul 16 '15 at 10:08
3

It is possible using sed. Pipe the input to the below.

| sed 's/\(^.\{12\}\)\([^,]\+\),\([^,]\+\)/\1\2\n\1\3/'

output

3923 001    L05 LV
3923 001    L05 RM
3923 002    L12 RA
3923 002    L12 LA
3923 003    I06 ALL
3923 004    G04 RV
3923 004    Z09 ALL

Here is the source to handle input with multiple ","

For original input without tab, use

| perl -ne '/,/ && do {chomp;s/^(.{12})(.+)/$1,$2/; @l = split(","); foreach $a (@l[1 .. $#l]) {print "$l[0]$a\n";};1;} || do {print;}'

If input has tab, use

| perl -ne '/,/ && do{chomp; s/^([^\t]+\t)(.+)/$1,$2/; @l = split(","); foreach $a (@l[1 .. $#l]) {print "$l[0]$a\n";};1;} || do {print;}'
13
  • Any reason for downvoting.
    – soumen
    Jul 16 '15 at 8:56
  • Downvoted...It adds extra blank line for every split
    – Thushi
    Jul 16 '15 at 8:58
  • I added an extra new line based on previous input. It seems like the input is now modified.
    – soumen
    Jul 16 '15 at 9:00
  • Based on your current output, I figure you are trying pick the prefix upto 12th Character and not 10th. Can you clarify. I have already updated my solution.
    – soumen
    Jul 16 '15 at 9:04
  • The columns are not aligned
    – Thushi
    Jul 16 '15 at 9:04
1

Possible solution with awk:

awk -F" " '{ x = $3 " " $4 " " $5; split(x, a, ","); for (i in a) { print $1, $2 "\t" a[i]; } }' file

Output should be:

3923 001    L05 LV
3923 001    L05 RM
3923 002    L12 RA
3923 002    L12 LA
3923 003    I06 ALL 
3923 004    G04 RV
3923 004    Z09 ALL

And if your input contains multiple , as in comments: 3923 001 L05 LV,L05 RM,L09 AB you can try this:

awk -F" " '{ x = $3; for (i = 4; i <= NF; i++) { x = x " " $i; } split(x, a, ","); for (i in a) { print $1, $2 "\t" a[i]; } }' file
4
  • 1
    Missing the - from the F flag.
    – 123
    Jul 16 '15 at 8:56
  • @User112638726, sorry, thanks, I'll edit it.
    – taliezin
    Jul 16 '15 at 8:57
  • Downvoting....What if he has multiple "," . Example: 3923 001 L05 LV,L05 RM,L09 AB. In your case it will cut the AB
    – Thushi
    Jul 16 '15 at 9:31
  • @taliezin: Works!!!
    – Thushi
    Jul 16 '15 at 9:44
1

Simplyfied variant of User112638726 answer

sed ':1;s/\(\(.*\s\s\+\)[^,]\+\),/\1\n\2/;t1'
sed -r ':1;s/((.+\s\s+)[^,]+),/\1\n\2/;t1'

will choice repeated part as «any symbols before 2(or more) spaces».

Then you can pipe output through

uniq -s 10
1
  • If you are only using a single t/b, you don't need to assign it a name.
    – 123
    Jul 16 '15 at 10:36
1

You can use awk and set the field separator to either spaces or comma. Then, loop in blocks of 2, printing the first and second fields together with blocks of two:

$ awk -v FS='(\\s+|,)' '{for (i=3; i<=NF; i+=2) print $1, $2, $i, $(i+1)}' file
3923 001 L05 LV
3923 001 L05 RM
3923 002 L12 RA
3923 002 L12 LA
3923 003 I06 ALL
3923 004 G04 RV
3923 004 Z09 ALL

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.