
Мне нужно заменить _
(подчеркивание) на ?
(вопросительный знак) в файле, содержащем адреса электронной почты.
Файл выглядит следующим образом:
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
вхождением в ту же строку, и только в тех строках, которые содержат обе строки.