заменить символ из строки, которая находится между первым и вторым поиском, используя sed или awk

заменить символ из строки, которая находится между первым и вторым поиском, используя sed или awk

Мне нужно заменить _(подчеркивание) на ?(вопросительный знак) в файле, содержащем адреса электронной почты.

Файл выглядит следующим образом:

EFT_020034-E015133  20140624    /ACC/[email protected]         SHR    END 
EFT_020034-E015133  20140624    /ACC/[email protected]     SHR    END
EFT_020034-E015133  20140624    /ACC/[email protected]        SHR    END

Ожидаемый результат:

EFT_020034-E015133  20140624    /ACC/[email protected]         SHR    END 
EFT_020034-E015133  20140624    /ACC/[email protected]     SHR    END
EFT_020034-E015133  20140624    /ACC/[email protected]        SHR    END

Как я могу это сделать вседилиawkне затрагивая другие подчеркивания и только подчеркивание между EMAIL+(constant) и SHR(constant). Измененное содержимое следует сохранить в новом файле.

решение1

awk сделает это:

$ awk '{ gsub("_", "?", $3) ; print }' < data
EFT_020034-E015133 20140624 /ACC/[email protected] SHR END
EFT_020034-E015133 20140624 /ACC/[email protected] SHR END
EFT_020034-E015133 20140624 /ACC/[email protected] SHR END

Адреса электронной почты указаны в поле 3, поэтому мы заменяем _на ?только в поле 3, включая случаи, когда их больше одного _, используяgsub.

решение2

С sedвами можно сделать:

sed -e :1 -e 's/_\([^+]*@\)/?\1/;t1'

То есть заменить _последовательностью не- +символов, за которой следует @последовательность ?символов, и повторять процесс до тех пор, пока они не совпадут.

Или сделать это только между EMAIL+и SHR:

sed -e :1 -e 's/\(EMAIL+.*\)_\(.*SHR\)/\1?\2/;t1'

Если вы хотите учитывать только те строки, которые начинаются с ^EFT, вы можете добавить -e '/^EFT/!b', чтобы оставить в стороне те, которые не нравятся:

sed -e '/^EFT/!b' -e :1 -e 's/\(EMAIL+.*\)_\(.*SHR\)/\1?\2/;t1'

Обратите внимание, что для ввода типа:

EFT EMAIL+ foo_bar SHR bar_baz EMAIL+ SHR

Оба подчеркивания будут заменены, поскольку они оба находятся между EMAIL+и SHR.

Чтобы этого избежать, можно сделать что-то вроде:

sed '
  /^EFT/!b # leave the non-EFT lines alone (branch out)
  s/%/%p/g; s/</%l/g; s/>/%r/g; # escape the <>% characters with %
  s/EMAIL+/</g; s/SHR/>/g; # replace EMAIL+ and SHR with < and >
  :1
  s/\(<[^<>]*\)_\([^<>]*>\)/\1?\2/; t1
  s/</EMAIL+/g; s/>/SHR/g; # restore EMAIL+ and SHR
  s/%r/>/g; s/%l/</g; s/%p/%/g; # restore the escaped <>%'

решение3

sed '/.*EMAIL+\(.*\)SHR.*/{
    h;s//\1/;y/_/?/;G
    s/\(.*\)\n\(.*EMAIL+\).*SHR/\2\1SHR/}'

Это должно выполнить работу довольно надежно — он заменит все _символы ?между последним EMAIL+вхождением в строку и последним SHRвхождением в ту же строку, и только в тех строках, которые содержат обе строки.

Связанный контент