Які символи мені потрібні для виходу під час використання sed у скрипті sh?


248

Візьміть такий сценарій:

#!/bin/sh
sed 's/(127\.0\.1\.1)\s/\1/' [some file]

Якщо я спробую запустити це в sh( dashтут), воно не вдасться через дужки, які потрібно уникнути. Але мені не потрібно уникати самих відхилень (між октетами, або в \sабо \1). Яке правило тут? А як щодо того, коли мені потрібно використовувати {...}або [...]? Чи є список того, що я роблю і мені не потрібно бігти?


1
Ось функція bash для перетворення шляхів для використання з SED:function sedPath { path=$((echo $1|sed -r 's/([\$\.\*\/\[\\^])/\\\1/g'|sed 's/[]]/\[]]/g')>&1) } #Escape path for use with sed
user2428118


Dura lex, sed sed
Немо

Відповіді:


281

Тут є два рівні тлумачення: оболонка і sed.

У оболонці все між одиничними цитатами інтерпретується буквально, крім самих одиничних лапок. Ви можете ефективно мати єдину цитату між окремими цитатами, написавши '\''(закрити єдину цитату, одну буквальну єдину цитату, відкриту єдину цитату).

Sed використовує основні регулярні вирази . У BRE, для того, щоб їх було досліджено буквально, символів $.*[\^потрібно процитувати, попередньо наклавши зворотну косу рису, за винятком внутрішніх наборів символів ( […]). Букви, цифри і (){}+?|не повинні бути укладені в лапки (ви можете піти з посиланням на деякі з них в деяких реалізаціях). Послідовності \(, \), \n, і в деяких реалізаціях \{, \}, \+, \?, \|і інший зворотний слеш + буквено - цифрові мають особливе значення. Ви можете піти від того, щоб не вказувати $^деякі позиції в деяких реалізаціях.

Крім того, вам знадобиться зворотна косої риси раніше, /якщо вона буде відображатися в регулярному виразі поза дужками виразів. Ви можете вибрати альтернативний символ як роздільник, написавши, наприклад, s~/dir~/replacement~або \~/dir~p; вам знадобиться зворотний нахил перед роздільником, якщо ви хочете включити його в BRE. Якщо ви обрали персонажа, який має особливе значення у BRE, і ви хочете включити його буквально, вам знадобляться три зворотні риски; Я не рекомендую цього, оскільки це може поводитися по-різному в деяких реалізаціях.

Коротше кажучи, для sed 's/…/…/':

  • Запишіть регулярні вирази між одиничними лапками.
  • Використовуйте '\''для завершення з однією цитатою в регулярному виразі.
  • Поставте зворотну косу рису перед $.*/[\]^та лише тими символами (але не всередині дужкових виразів). (Технічно ви не повинні ставити зворотну косу рису раніше, ]але я не знаю про реалізацію, яка розглядає ]і не \]відрізняється від дужок виразів.)
  • Всередині дужки вираз, -який потрібно досліджувати буквально, переконайтеся, що він перший чи останній ( [abc-]або [-abc], ні [a-bc]).
  • Всередині виразного дужка, для того, ^щоб досліджуватися буквально, переконайтесь, що він не перший (використовуйте [abc^], ні [^abc]).
  • Щоб включити ]до списку символів, відповідних виразі дужки, зробіть його першим символом (або першим після ^заперечним набором): []abc]або [^]abc](ні, [abc]]ні[abc\]] ).

У тексті заміни:

  • &і їх \потрібно цитувати, передуючи їх зворотній косою рисою, як це роблять роздільник (як правило /) та нові рядки.
  • \слідом за цифрою має особливе значення. \Далі буква має особливе значення (спеціальні символи) у деяких реалізаціях, а \за ними - інші символьні засоби \cабо cзалежно від реалізації.
  • За допомогою одиничних лапок навколо аргументу ( sed 's/…/…/') використовуйте '\''для додавання єдиної лапки в текст заміни.

Якщо шрифт або текст заміни надходить із змінної оболонки, пам’ятайте про це

  • Режекс - BRE, а не буквальний рядок.
  • У регулярному виразі новий рядок повинен бути виражений як \n(що ніколи не збігатиметься, якщо у вас немає іншого sedкоду, який додає символи нового рядка до простору шаблону). Але зауважте, що він не працюватиме в дужкових виразах з деякими sedреалізаціями.
  • У тексті заміни &, \та нові рядки потрібно цитувати.
  • Розмежувач потрібно вказати (але не всередині дужкових виразів).
  • Використовуйте подвійні лапки для інтерполяції: sed -e "s/$BRE/$REPL/".

Якщо уникнути фактичного символу підстановки (*), ви можете використовувати подвійний нахил ( \\*). Приклад:echo "***NEW***" | sed /\\*\\*\\*NEW\\*\\*\\*/s/^/#/
небезпека89

43

Проблема, з якою ви стикаєтеся, не пов’язана з інтерполяцією оболонки та втечею - це тому, що ви намагаєтесь використовувати синтаксис розширеного регулярного вираження, не передаючи sed -rабо --regexp-extendedпараметр.

Змініть свою лінійку sed від

sed 's/(127\.0\.1\.1)\s/\1/' [some file]

до

sed -r 's/(127\.0\.1\.1)\s/\1/' [some file]

і це буде працювати так, як я вважаю, ви маєте намір.

За замовчуванням sed use використовує основні регулярні вирази (think grep style), які потребують наступного синтаксису:

sed 's/\(127\.0\.1\.1\)[ \t]/\1/' [some file]

У мене знову з’явилася ця проблема, і я забув прокрутити вниз, щоб знайти рішення, яке я схвалив минулого разу. Знову дякую.
isaaclw

Дуже дякую. Додавання -rяк варіант було те, що було потрібно в моєму випадку.
HelloGoodbye

15

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

Тож якщо ви хочете, щоб sed бачив, як s/\(127\.0\.1\.1\)\s/\1/навколо нього ставляться одиничні лапки, і оболонка не буде торкатися круглих дужок або зворотних косих ринків. Якщо вам потрібно інтерполювати змінну оболонки, поставте лише ту частину в подвійних лапках. Напр

sed 's/\(127\.0\.1\.1\)/'"$ip"'/'

Це позбавить вас від проблеми запам’ятати, які метахарактеристики оболонок не уникнути подвійних лапок.


Я хочу sedпобачити s/(127\.0\.1\.1)/..., але ставити це в скрипті оболонки як - не працює. Те, що ви говорите про оболонку, яка не торкається круглих дужок, здається неправильним. Я відредагував своє запитання, щоб детальніше.
дет

3
Оболонка не торкається круглих дужок. Вам потрібні зворотні коси, тому що sed потрібно їх бачити. sed 's/(127\.0\.1\.1)/IP \1/'не вдається, тому що sed потрібно бачити \(і \)для групового синтаксису, а не (і ).
Кайл Джонс

facepalm Це не на сторінці man, але це є в деяких онлайн-посібниках, які я знайшов. Це нормально для regex, тому що мені ніколи не доводилося використовувати його в бібліотеках регулярних виразів (наприклад, Python)?
detly

3
Для традиційних команд Unix існують основні регулярні вирази та розширені регулярні вирази. Деталі . sed використовує основні регулярні вирази, тому зворотні риски потрібні для групового синтаксису. Perl і Python вийшли за рамки навіть розширених регулярних виразів. Поки я розмовляв навколо, я знайшов надзвичайно інформативну діаграму, яка ілюструє, який заплутаний міхун ми вигадуємо, коли ми грізно вимовляємо "регулярний вираз".
Кайл Джонс

1
Я також додам, що єдиний символ, який не може бути використаний у межах однієї лапки, - це одна цитата.
enzotib
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.