Як виявити кінець рядка з sed


15

Я шукаю спосіб виконати заміну лише тоді, коли останній символ є новим рядком, використовуючи sed.

Наприклад:

lettersAtEndOfLine

замінюється, але це не так:

lettersWithCharacterAfter&

Оскільки sedне працює з новими рядками, це не так просто

$ sed -E "s/[a-zA-Z]*\n/replace/" file.txt

Як це можна досягти?

Відповіді:


21

За допомогою стандарту sedви ніколи не побачите новий рядок у тексті, прочитаному з файлу. Це тому, що sedчитається рядок за рядком, і тому в кінці тексту поточного рядка в sedпросторі шаблону немає нового рядка . Іншими словами, sedчитає дані з обмеженим рядком, і роздільники не є частиною того, що sedбачить сценарій.

Регулярні вирази можуть бути закріплені в кінці рядка, використовуючи $(або на початку, використовуючи ^). Прив’язування виразу на початку / в кінці рядка змушує його відповідати саме там, а не лише де-небудь на лінії.

Якщо ви хочете замінити що-небудь, що відповідає шаблону [A-Za-z]*в кінці рядка, чимось, то закріпіть такий зразок:

[A-Za-z]*$

... змусить його відповідати в кінці рядка і ніде більше.

Однак, оскільки [A-Za-z]*$також нічого не відповідає (наприклад, порожній рядок, присутній в кінці кожного рядка), вам потрібно примусити відповідати щось , наприклад, вказавши

[A-Za-z][A-Za-z]*$

або

[A-Za-z]\{1,\}$

Отже, ваш командний рядок sed буде таким

$ sed 's/[A-Za-z]\{1,\}$/replace/' file.txt

Я тут не користувався -Eвимикачем, тому що він не потрібен. З ним можна було писати

$ sed -E 's/[A-Za-z]+$/replace/' file.txt

Це питання смаку.


Коментарі не для розширеного обговорення; ця розмова була переміщена до чату .
Kusalananda

3
sed "s/[a-zA-Z]*$/replace/" input.txt > result.txt

Або довгий складний непотрібний спосіб:

Я з’ясував, це можна зробити, все ще використовуючи sed, за допомогою tr. Ви можете призначити інший символ, який представляє кінець рядка. Має бути використаний інший тимчасовий символ, у цьому випадку "" ". Давайте використаємо "~" для позначення кінця рядка:

tr '\n' '`' <input.txt >output.txt
sed -i "s/`/~`/" output.txt
tr '`' '\n' <output.txt >result.txt

А потім, щоб виконати фактичний пошук та заміну, використовуйте "~", а не "\ n":

sed -i -E "s/[a-zA-Z]*~/replace/" result.txt

А потім очистіть зайвий символ в інших рядках:

sed -i "s/~//" result.txt

Очевидно, що все це може бути об'єднано, і в результаті вийде щось на зразок:

tr '\n' '`' <input.txt | sed -e "s/`/~`/" | tr '`' '\n' | sed -E -e "s/[a-zA-Z]*~/replace/" | sed "s/~//" > result.txt

3
Не впевнений, що я розумію ... Чому ви просто не прив’яжіть до кінця рядка $? наприкладs/[a-zA-Z]*$/replace/
don_crissti

1
2 бали: 1) краще використовувати \+замість цього, *оскільки останній дозволяє нульові літери в кінці рядка; 2) Ви можете використовувати клас символів [[:alpha:]]. Отже:sed 's/[[:alpha:]]\+$/replace/' file
Глен Джекман

@glennjackman Що таке зворотний нахил перед плюсом? Чи не відповідало б цьому символу додавання?
Меттью Д. Скоулфілд

1
GNU sed без -rпараметра використовує цей синтаксис регулярного вираження .
Глен Джекман

0

З опублікованого вами фрагмента коду (зламаного) коду, здається, ви хочете також замінити новий рядок. У такому випадку прив'язка регулярного вирівнювання сама по собі не може вам допомогти. Далі є рішення:

sed '/[[:alpha:]]\+$/{N;s/[[:alpha:]]\+\n/replace/}' your_file

Зломаний:

  • /[a-zA-Z]\+$/{} означає застосувати все, що потрапляє всередину фігур, до ліній, які відповідають регулярному вираженню.
  • Режекс - це те, що використовує прив'язку, як видно з вашої власної відповіді , модифіковану для врахування коментарів Глена Джекмана .
  • Всередині фігурних Nкоштів означає "додати наступний рядок до активного буфера" (що sedназиває "простір візерунка")
  • Нарешті, s///заява - це ваша необхідна заміна. Тепер він працює, тому що простір шаблону містить дві послідовні лінії, тому нова лінія є його частиною.

0

Щоб знайти кінець рядка, просто скористайтеся знаком $ :

Без кінцевого якірного рядка:

sed -n '/pattern/p' file 

Без кінцевого якірного рядка:

sed -n '/pattern$/p' file
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.