g_p
g_p

Reputation: 5506

sed multiple repacement in a line

It may be a very basic question but I am not able to form the sed on liner for this.

Consider this line

foo@some_text/48183 bar@another-test/22787 xyz@some_another_text/2291

I want to replace everything from "@" to space separated by comma. So my expected output should look like

foo,bar,xyz

I was trying sed -e 's/@.*[^ ]/,/g' to replace till space however it is replacing whole whole line(not so good in writing regular exp).

Any help will be appreciated.

Upvotes: 4

Views: 58

Answers (4)

Allan
Allan

Reputation: 12456

You can also do it the other way around even if it might be a bit more pipy.

$ echo "foo@some_text/48183 bar@another-test/22787 xyz@some_another_text/2291" | (tr ' ' ',' | grep -oP '(?=,|^)[^@]+' | tr -d '\n'; echo "")
foo,bar,xyz

Instead of replacing, part of the string you can directly extract the relevant parts.

Explanations:

  • tr ' ' ',' in order to replace all spaces by commas.
  • grep -oP '(?=,|^)[^@]+' to fetch everything before the @. It uses perl regex with lookaround (imposing the constraint that the preceding character is either a comma or the beginning of the string and accept all the characters except @.
  • tr -d '\n' is used to remove the EOL inserted by grep
  • the echo "" may be omitted if you do not need to have an ending \n. You can then simplify the command in tr ' ' ',' | grep -oP '(?=,|^)[^@]+' | tr -d '\n'

Upvotes: 2

RavinderSingh13
RavinderSingh13

Reputation: 133760

Following awk may help you here.

awk 'BEGIN{OFS=","}{for(i=1;i<=NF;i++){sub(/@.*/,"",$i)}} 1'  Input_file

Solution 2nd: Taking code from Wiktor Stribizew's post and modifying it a bit to convert it to a single sed now.

sed -E 's/([^@]+)@[^[:space:]]*[[:space:]]*/\1,/g;s/,$//'  Input_file

Upvotes: 2

Valdi_Bo
Valdi_Bo

Reputation: 31011

The basic problem with the match part of your regex (@.*[^ ]) is that .* matches almost the whole rest of the source string after the first @ (a quite common error) and [^ ] matches the last non-space char.

If you use @\S+\s* as the match part, then \S+ matches "non-space" part (e.g. some_text/48183) and \s* matches optional spaces thereafter.

This replacement gives foo,bar,xyz,, so you should somehow delete the last comma.

Upvotes: 2

Wiktor Stribiżew
Wiktor Stribiżew

Reputation: 627469

You may find and capture any 1+ chars other than @ before a @ char, then match @ and any 0+ chars other than whitespace followed with 0+ whitespace chars, and replace all that with a placeholder to Group 1 and a comma. Then, you will have to remove the trailing comma.

See a sed demo:

s='foo@some_text/48183 bar@another-test/22787 xyz@some_another_text/2291'
echo "$s" | sed -E 's/([^@]+)@[^[:space:]]*[[:space:]]*/\1,/g' | sed 's/,$//'

Note that you may also use sed 's/\([^@][^@]*\)@[^[:space:]]*[[:space:]]*/\1,/g' insead of the POSIX ERE version. In BRE POSIX, you should escape ( and ) to form a capturing group, and + quantifier should be escaped, or replaced with a aa* construction.

Details

  • ([^@]+) - Capturing group 1: 1+ chars other than @
  • @ - a @ char
  • [^[:space:]]* - 0+ chars other than whitespace
  • [[:space:]]* - 0+ whitespace chars

The \1 is a placeholder for the text captured with the capturing group #1.

The second sed 's/,$//' is used to remove the trailing , at the end of the string.

Upvotes: 3

Related Questions