Using cut/awk/sed with two different delimiters

19,883

Solution 1

Assuming you won't ever have more than one @ symbol,

sed 's/_.*@/@/' file.txt

...should work.

Solution 2

Not sure what you're really doing with this but your could do it like so with sed:

$ sed 's/\(case\).*\(@test.com\)/\1\2/' 87529.txt 
[email protected]
[email protected]
[email protected]

This effectively trims everything out between case and the @.

You can do something similar with awk:

$ awk -F@ '{split($1,a,"_"); print a[1]"@"$2}' 87529.txt 

Also can be done with perl (similar to evilsoup's approach):

$ perl -p -e 's/_.*@/@/g' 87529.txt 

Or you can make use of perl's lookahead facility:

$ perl -p -e 's/_.*(?=@)//g' 87529.txt 

NOTE: Lookahead and lookbehind's in perl allow you to include strings in the regex pattern that you're matching on, without having them be included in the operation that will be performed against the regex. Think of them as dynamic versions of the caret (^) - beginning of a line, and dollar ($) - end of the line. This a little less hacky then having to add the @ back in, after removing it.

Solution 3

If the lines may contain more than one @:

sed 's/^\([^@_]*\)_[^@]*@/\1@/'

Or:

awk -F@ -vOFS=@ 'NF >= 2 {sub(/_.*/,"",$1)};1'

Solution 4

If your shell supports parameter expansion, you can do something like

while read line; do
    printf "%s\n" "${line%%_*}@${line#*@}"
done < your_file_here

The expansion ${line%%_*} removes the leftmost _ and everything following it while the expansion ${line#*@} removes the leftmost @ and everything preceding it.

Share:
19,883

Related videos on Youtube

Sten Kin
Author by

Sten Kin

Updated on September 18, 2022

Comments

  • Sten Kin
    Sten Kin over 1 year

    I have the following cases:

     [email protected]
     [email protected]
     [email protected]
    

    I'm trying to convert these to

     [email protected]
     [email protected]
     [email protected]
    

    So it should remove everything from the first '_' (including it) to the @ (not including that).

    I have something, but it doesn't really work correctly:

    Based on this thread: Cut based on Two Delimiters at one go, and this U&L Q&A: Splitting string by the first occurrence of a delimiter.

    sed 's/^.*_\([^ ]*\) .*\@\([^$]*\)$/\1 \2/' infile
    

    But no luck. Anyone want to take a chime at it?

  • Jeff Hewitt
    Jeff Hewitt over 10 years
    I think you need global substitutions (i.e. s/_/ /g;...)
  • Jeff Hewitt
    Jeff Hewitt over 10 years
    @manatwork Beautiful. I would say this merits to be in answer of its own with a short explanation perhaps...
  • Stéphane Chazelas
    Stéphane Chazelas over 10 years
    However note that performance will be very poor on big files as anything using loops in bash, and that assumes all lines contain one @ and one _ before the left-most @ (and the other usual problems when using read with -r and without setting IFS)