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

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

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

 EFT_020034-E015133 20140624 /ACC/EMAIL+test_1@mysite.com SHR END EFT_020034-E015133 20140624 /ACC/EMAIL+test_123_abc@yoursite.net SHR END EFT_020034-E015133 20140624 /ACC/EMAIL+test_456@theirsite.com SHR END 

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

 EFT_020034-E015133 20140624 /ACC/EMAIL+test?1@mysite.com SHR END EFT_020034-E015133 20140624 /ACC/EMAIL+test?123?abc@yoursite.net SHR END EFT_020034-E015133 20140624 /ACC/EMAIL+test?456@theirsite.com SHR END 

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

  • Улучшить команду sed для замены первого экземпляра символа и всех следующих символов?
  • Использовать sed или awk для объединения строк в определенном шаблоне?
  • Как сокращать / путь / в / файл в / p / t / файл
  • Использование sed для добавления URL-адреса в начало каждой строки
  • Удалить слово после матча
  • Греблирование фигур строки для создания новой строки
  • Помощь с sed - удаление определенных строк с определенной строкой
  • awk: Столбцы не печатаются, когда конкатенация строк передается как командная строка
  • 3 Solutions collect form web for “замените символ из строки, которая находится между первым и вторым поиском, используя sed или awk”

    awk сделает следующее:

     $ awk '{ gsub("_", "?", $3) ; print }' < data EFT_020034-E015133 20140624 /ACC/EMAIL+test?1@mysite.com SHR END EFT_020034-E015133 20140624 /ACC/EMAIL+test?123?abc@yoursite.net SHR END EFT_020034-E015133 20140624 /ACC/EMAIL+test?456@theirsite.com SHR END 

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

    С sed вы могли бы сделать:

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

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

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

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

    Если вы хотите рассматривать только строки, начинающиеся с ^EFT , вы можете добавить a -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 <>%' 
     sed '/.*EMAIL+\(.*\)SHR.*/{ h;s//\1/;y/_/?/;G s/\(.*\)\n\(.*EMAIL+\).*SHR/\2\1SHR/}' 

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

    Linux и Unix - лучшая ОС в мире.