Чергування генерогенезу / або оператора (foo | bar) в GNU або BSD Sed


28

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

$ echo 'cat
dog
pear
banana
cat
dog' | sed 's/cat|dog/Bear/g'
cat
dog
pear
banana
cat
dog

$ echo 'cat
dog
pear
banana
cat
dog' | sed 's/cat\|dog/Bear/g'
cat
dog
pear
banana
cat
dog

Відповіді:


33

За замовчуваннямsed використовується POSIX Basic регулярні вирази , які не включають |оператора чергування. Багато версій sed, включаючи GNU і FreeBSD, підтримують перемикання на розширені регулярні вирази , які включають |чергування. Як ви , який змінюється: GNU СЕД використовує-r , в той час як FreeBSD , NetBSD , OpenBSD , і OS X СЕД використання -E. Інші версії здебільшого не підтримують його взагалі. Ви можете використовувати:

echo 'cat dog pear banana cat dog' | sed -E -e 's/cat|dog/Bear/g'

і він буде працювати на цих системах BSD та sed -rз GNU.


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

У коментарі зазначається, що версії BSD також підтримуються -rяк бездокументований псевдонім. OS X все ще не існує сьогодні, і до старих машин NetBSD і OpenBSD я не маю жодного доступу, але NetBSD 6.1 - один. Комерційних об'єднань, до яких я можу звернутись повсюдно, немає. Отже, при тому, що питання про портативність стає досить складним на даний момент, але проста відповідь полягає в тому, щоб перейти до цього,awk якщо вам це потрібно, що використовує ERE скрізь.


Три BSDs ви згадали весь каталог підтримка , яка надається -rваріант як синонім -Eдля сумісності з GNU СЕД. OpenBSD і OS X sed -Eінтерпретуватимуть трубу, що втекла, як дослівну, а не як оператор чергування. Ось робоче посилання на сторінку чоловічої сторінки NetBSD, і ось для OpenBSD, якому не виповнилося десяти років.
Дамієн



9

Це відбувається тому (a|b), що це розширений регулярний вираз, а не базовий регулярний вираз. Скористайтеся -Eопцією для вирішення цього питання.

echo 'cat
dog
pear
banana
cat
dog'|sed -E 's/cat|dog/Bear/g'

На sedчоловіковій сторінці:

 -E      Interpret regular expressions as extended (modern) regular
         expressions rather than basic regular expressions (BRE's).

Зауважте, що -rце ще один прапор для тієї ж речі, але -Eвін більш портативний і навіть буде в наступній версії специфікацій POSIX.


6

Портативний спосіб зробити це - і більш ефективний спосіб - з адресами. Ви можете зробити це:

printf %s\\n cat dog pear banana cat dog |
sed -e '/cat/!{/dog/!b' -e '};cBear'

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

Це, ймовірно , варто відзначити також , що будь-яка заява , слідуючи !bв цій sedкоманді може тільки відповідати по рядку , що містить або рядку dogабо cat- так що ви можете виконувати подальші випробування без будь - якої небезпеки сполучати лінії , яка - це значить , тепер ви можете застосувати правила лише до того чи іншого.

Але це далі. Ось вихід із наведеної команди:

###OUTPUT###
Bear
Bear
pear
banana
Bear
Bear

Ви також можете портативно реалізувати таблицю пошуку із зворотними налаштуваннями.

printf %s\\n cat dog pear banana cat dog |
sed '1{x;s/^/ cat dog /;x
};G;s/^\(.*\)\n.* \1 .*/Bear/;P;d'

Налаштування цього простого прикладу набагато більше, але це може зробити набагато більш гнучкими sedсценарії з часом.

У першому рядку я xзмінюю простір утримування та простір візерунка, а потім вставляю собаку <space>котячої кішки<space><space> в простір перед тим, як xзмінити їх.

З цього Gмоменту і в кожному наступному рядку я вміщую простір, доданий до простору шаблону, а потім перевіряю, чи всі символи від початку рядка до нового рядка, який я щойно додав у кінці, відповідають рядку, оточеному пробілами після нього. Якщо так, я замінюю весь лот на Bear, а якщо ні, то шкоди не завдано, тому що я наступним чином Pвказую лише до першого зустрічається нового рядка в просторі шаблону, тоді dвибираю його все.

###OUTPUT###
Bear
Bear
pear
banana
Bear
Bear

І коли я кажу гнучко, я маю на увазі це. Ось вона замінює кота на BrownBear та собаку на BlackBear :

printf %s\\n cat dog pear banana cat dog |
sed '1{x;s/^/ 1cat Brown 2dog Black /;x
};G;s/^\(.*\)\n.* [0-9]\1 \([^ ]*\) .*/\2Bear/;P;d'

###OUTPUT###
BrownBear
BlackBear
pear
banana
BrownBear
BlackBear

Звичайно, можна значно розширити вміст таблиці пошуку - я взяв цю ідею з електронних листів Грега Уббена на цю тему, коли в 90-х він описав, як він сконструював грубий калькулятор з одного sed s///твердження.


1
феу, +1. У вас є схильність до роздумів поза межами коробки, я мушу сказати
iruvar

@ 1_CR - Дивіться мою останню редакцію - не мою ідею - що не означає, що я не ціную це, і вважаю це компліментом. Але я люблю дарувати кредит там, де це належить.
mikeserv

1

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

ви можете сказати : sed -E '/^\/\*!(40103|40101|40111).*\/;$/d'

або помістіть це у свій файл sed:

/^\/\*!40103.*\/;$/d
/^\/\*!40101.*\/;$/d
/^\/\*!40111.*\/;$/d

0

Ось методика, яка не використовує жодних варіантів реалізації sed(наприклад -E, -r). Замість того, щоб описувати шаблон як єдиний регулярний вираз cat|dog, ми можемо просто запустити sedдвічі:

echo 'cat
dog
pear
banana
cat
dog' | sed 's/cat/Bear/g' | sed 's/dog/Bear/g'

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

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

for pattern in cat dog owl; do
    sed -i "s/${pattern}/Bear/g" myfile
done
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.