Хотите заменить только первое вхождение с sed

Исходный файл

claudio antonio claudio michele 

Я хочу изменить только первое появление «claudio» с «claudia», поэтому результат файла

 claudia antonio claudio michele 

я пытался

 sed -e '1,/claudio/s/claudio/claudia/' nomi 

Но выполняйте глобальную замену. Почему?

  • sed: что означает «/»?
  • sed для вставки строки после последней соответствующей строки в файле
  • sed строка не соответствует. Зачем?
  • sed inline editing не работает для нескольких операторов sed
  • Проблема с sed
  • Извлечь тройной обратный код, огороженный кодовым блоком `` `выдержки из файла уценки
  • Что не так с экранированной новой строкой в ​​этой команде sed?
  • Замена захваченной группы с помощью SED
  • 7 Solutions collect form web for “Хотите заменить только первое вхождение с sed”

    Если вы используете GNU sed , попробуйте:

     sed -e '0,/claudio/ s/claudio/claudia/' nomi 

    sed не запускает проверку для регулярного выражения, которое заканчивает диапазон, до тех пор, пока строка, начинающая этот диапазон.

    От man sed (POSIX manpage, акцент мой):

     Команда редактирования с двумя адресами должна выбирать полный диапазон
     из первого пространства шаблонов, которое соответствует первому адресу через 
      следующее пространство шаблона , совпадающее со вторым. 
    

    Использование awk

    Диапазоны в awk работают больше, как вы ожидали:

     $ awk 'NR==1,/claudio/{sub(/claudio/, "claudia")} 1' nomi claudia antonio claudio michele 

    Объяснение:

    • NR==1,/claudio/

      Это диапазон, который начинается с строки 1 и заканчивается первым вступлением claudio .

    • sub(/claudio/, "claudia")

      Пока мы находимся в диапазоне, эта команда подстановки выполняется.

    • 1

      Это критическая стенограмма awk для печати строки.

    Вот еще 2 дополнительных усилия с sed: они оба читают весь файл в одну строку, затем поиск заменяет только первый.

     sed -n ':a;N;$bb;ba;:b;s/\(claudi\)o/\1a/;p' file sed -n '1h;1!H;${g;s/\(claudi\)o/\1a/;p;}' file 

    С комментарием:

     sed -n ' # don't implicitly print input :a # label "a" N # append next line to pattern space $bb # at the last line, goto "b" ba # goto "a" :b # label "b" s/\(claudi\)o/\1a/ # replace p # and print ' file 
     sed -n ' # don't implicitly print input 1h # put line 1 in the hold space 1!H # for subsequent lines, append to hold space ${ # on the last line g # put the hold space in pattern space s/\(claudi\)o/\1a/ # replace p # print } ' file 

    Вы можете использовать awk с флагом, чтобы узнать, была ли замена уже выполнена. Если нет, продолжайте:

     $ awk '!f && /claudio/ {$0="claudia"; f=1}1' file claudia antonio claudio michele 

    На самом деле это очень просто, если вы просто установите небольшую задержку – нет необходимости идти на недостоверные расширения:

     sed '$H;x;1,/claudio/s/claudio/claudia/;1d' <<\IN claudio antonio claudio michele IN 

    Это просто переводит первую строку на вторую, а вторую на третью и т. Д.

    Он печатает:

     claudia antonio claudio michele 

    И еще один вариант

     sed --in-place=*.bak -e "1 h;1! H;\$! d;$ {g;s/claudio/claudia/;}" -- nomi 

    Преимущество заключается в использовании двойной кавычки, поэтому вы можете использовать переменные внутри, т. Е.

     export chngFrom=claudio export chngTo=claudia sed --in-place=*.bak -e "1 h;1! H;\$! d;$ {g;s/${chngFrom}/${chngTo}/;}" -- nomi 

    Это также можно сделать без пространства удержания и без учета всех строк в пространстве шаблонов:

     sed -n '/claudio/{s/o/a/;bx};p;b;:x;p;n;bx' nomi 

    Объяснение: Мы пытаемся найти «claudio», и если мы это сделаем, мы перейдем к небольшому циклу печати-нагрузки между :x и bx . В противном случае мы печатаем и перезапускаем скрипт со следующей строкой.

     sed -n ' # do not print lines by default /claudio/ { # on lines that match "claudio" do ... s/o/a/ # replace "o" with "a" bx # goto label x } # end of do block p # print the pattern space b # go to the end of the script, continue with next line :x # the label x for goto commands p # print the pattern space n # load the next line in the pattern space (clearing old contents) bx # goto the label x ' nomi 
     sed -n '/claudia/{p;Q}' sed -n ' # don't print input /claudia/ # regex search { # when match is found do p; # print line Q # quit sed, don't print last buffered line { # end do block 
    Interesting Posts

    Что означают символы y / d / N?

    Две * разные * точки монтирования, имеющие * одинаковый * абсолютный путь (проблема привязки)

    Каковы режимы readline, раскладки клавиш и их привязки по умолчанию?

    Экспорт пакетов загрузки в Aptitude

    selinux разрешить порт портвейна 8332

    Почему мне не удается включить соединение на портах 80 и 443?

    Raspbian, Huawei E303, общедоступный IP-адрес

    Как использовать backspace в качестве ярлыка в Nautilus для перехода в каталог или предыдущий каталог

    Есть ли редактор XML-файлов для Linux с поддержкой grid view?

    Grep, но пусть первая строка через

    Откройте текстовый файл в терминале и автоматически обновите его, когда он будет изменен.

    Как повлиять на назначение подчиненных UID / GID при создании учетных записей пользователей?

    Как Linux отличается между открытием файла в режиме чтения и фактическим чтением данных из него?

    Совместное использование X-сервера (сеанса) на компьютерах

    Использование setfacl для создания рекурсивных разрешений для Apache с помощью rsync

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