Как изменить первое вхождение строки, содержащей шаблон? - PullRequest
9 голосов
/ 12 июля 2020

Мне нужно найти строку с первым вхождением шаблона, затем мне нужно заменить всю строку полностью новой.

Я нашел эту команду, которая заменяет первое вхождение шаблона, но не вся строка:

sed -e "0,/something/ s//other-thing/" <in.txt >out.txt

Если in.txt - это

one two three
four something 
five six
something seven

В результате я получаю out.txt:

one two three
four other-thing
five six
something seven

Однако, когда Я пытаюсь изменить этот код, чтобы заменить всю строку, следующим образом:

sed -e "0,/something/ c\COMPLETE NEW LINE" <in.txt >out.txt

Это то, что я получаю в out.txt:

COMPLETE NEW LINE
five six
something seven

Вы знаете, почему первая строка потеряна?

Ответы [ 3 ]

10 голосов
/ 12 июля 2020

Команда c\ удаляет все строки между первым совпадающим адресом и вторым совпадающим адресом включительно, когда используется с 2 адресами, и распечатывает текст, указанный после c\ при сопоставлении второй адрес. Если во входных данных нет строки, соответствующей второму адресу, он просто удаляет все строки (включительно) между первым совпадающим адресом и последней строкой. Поскольку вы хотите заменить только одну строку, вам не следует использовать команду c\ для диапазона адресов. При нормальном использовании за c\ сразу следует символ новой строки. Диапазон адресов 0,/regexp/ является расширением GNU sed, которое также будет пытаться сопоставить regexp в первой строке ввода, что отличается от 1,/regexp/ в этом аспекте. Итак, правильная команда в GNU sed может быть

sed '0,/something/{/something/c\
COMPLETE NEW LINE
}' < in.txt

или упрощена, как указано Sundeep

sed '0,/something/{//c\
COMPLETE NEW LINE
}' < in.txt

, или однострочным,

sed -e '0,/something/{//cCOMPLETE NEW LINE' -e '}' < in.txt

, если буквальный символ новой строки нежелателен.

Этот однострочник также работает, как указано potong:

sed '0,/something/!b;//cCOMPLETE NEW LINE' in.txt
6 голосов
/ 12 июля 2020

Это может сработать для вас (GNU sed):

sed '1!b;:a;/something/!{n;ba};cCOMPLETE NEW LINE' file

Настройте al oop, который будет работать только с первой строки.

Внутри l oop , если ключевое слово не найдено в текущей строке, распечатать текущую строку, выбрать следующую и повторять до конца файла или до тех пор, пока не будет найдено совпадение.

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

NB Команда c завершает любую дальнейшую обработку команд sed так же, как команда d.

Если есть строки в ввод после совпадения ключевого слова, отрицание адреса в начале цикла sed захватит эти строки и приведет к их печати без дальнейшей обработки.

Альтернатива:

sed 'x;/./{x;b};x;/something/h;//cCOMPLETE NEW LINE' file

Или (укажите c в GNU и bash):

sed $'0,/something/{//cCOMPLETE NEW LINE\n}' file
3 голосов
/ 12 июля 2020

Просто используйте awk:

$ awk '!done && sub(/something/,"other-thing"){done=1} {print}' file
one two three
four other-thing
five six
something seven

$ awk '!done && sub(/.*something.*/,"other-thing"){done=1} {print}' file
one two three
other-thing
five six
something seven

$ awk '!done && /something/{$0="other-thing"; done=1} {print}' file
one two three
other-thing
five six
something seven

и посмотрите, что вы можете тривиально сделать, если хотите заменить N-е вхождение something:

$ awk -v n=1 '/something/ && (++cnt == n){$0="other-thing"} {print}' file
one two three
other-thing
five six
something seven

$ awk -v n=2 '/something/ && (++cnt == n){$0="other-thing"} {print}' file
one two three
four something
five six
other-thing
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...