Відмінності між sed на Mac OSX та іншими "стандартними" sed?


61

У мене виникають деякі проблеми з використанням відповіді, наданої на цьому веб-сайті, на це запитання про команду sed для заміни порожнього рядка двома іншими рядками вмісту , і це виникло, якщо команда sed в Mac OS (10.6.7 для мене ) інакший. Я не думаю, що це так, але мені було цікаво, чи інші на цьому сайті думали інакше.

Відповіді:


43

Поведінка комунальних служб оболонок дійсно відрізняється між варіантами unix. Є багато варіантів Unix зі складною історією . Існують заходи щодо стандартизації, такі як стандарт POSIX та його суперсет Єдина специфікація UNIX . Більшість систем на сьогодні реалізує POSIX: 2001, також відомий як Єдина специфікація UNIX версії 3 , з незначними відхиленнями та безліччю розширень. Специфікація Single Unix не є навчальним посібником, але версія 3 читається, якщо ви вже маєте уявлення про те, що робить команда. Ви можете проконсультуватися, щоб дізнатися, чи є якась функція стандартною або розширенням певної системи.

Більшість користувачів Unix використовують Linux і не використовували жодного іншого варіанту. Linux постачається з утилітами GNU , які часто мають багато розширень до стандарту. Таким чином, ви знайдете там дуже багато коду, який працює на Linux, але не на інших уніках, оскільки він покладається на ці розширення.

Що стосується sed, проконсультуйтесь із специфікацією sed Single Unix про мінімум, який повинна підтримувати кожна система, сторінку man у вашій системі щодо того, що підтримує ваша реалізація, та посібник з GNU sed для того, що більшість людей там використовують.

Одне з нестандартних розширень GNU sed підтримує декілька команд, що працюють разом. Наприклад, ця програма GNU sed друкує всі рядки, що містять a, але змінюється bна cперший:

sed -ne '/a/ {s/b/c/g; p}'

{і }насправді є окремими командами, тому для повної переносимості їх потрібно вказати або в окремих рядках (у файлі), або в окремих -eаргументах (у командному рядку). Відсутність розділювача команд після {і використання ;в якості розділювача команд є поширеними розширеннями. Відсутність розділювача команд раніше }- менш поширене розширення. Це відповідає стандартам:

sed -n -e '/a/ {' -e 's/b/c/g' -e p -e '}'

Це нестандартно, але прийнято:

sed -ne '/a/ { s/b/c/g; p; }'

Ще одне нестандартне, але поширене розширення - це використання \nдля позначення нового рядка в sтексті заміни (використання в регулярному вираженні є стандартним). Портативний метод полягає у включенні зворотного косого рядка в сценарій sed. Інша поширена розширення \+, \?і \|в регулярних виразах означає один або кілька, в основному , один і чергування; переносні основні регулярні вирази не мають жодного з цих. Наприклад, перша команда - це непереносний спосіб заміни суміжних послідовностей пробілів на новий рядок; друга команда є еквівалентним стандартам.

sed -e 's/ \+/\n/'
sed -e 's/  */\
/'

Зауважте, що у всіх тих випадках, що стосуються розширень GNU, саме використання є нестандартним. sedСам GNU відповідає сумісності, оскільки робить речі, дозволені (але не обов'язкові, не визначені) стандартом. Бувають випадки, коли це не сумісне і де його використання POSIXLY_CORRECTв навколишньому середовищі може допомогти. Як і з s/[\n]//gцим, необхідно видалити люфт і nсимволи, але замість цього видалити нові рядки. Або поведінку Nкоманди в останньому рядку.
Стефан Шазелас

sed -ne '/a/ { s/b/c/g; p; }'є стандартним з моменту випуску стандарту 2016 року. Це було завжди портативно. Дивіться austingroupbugs.net/view.php?id=944&nbn=7
Stéphane Chazelas

60

OS X в даний час поставляється з FreeBSD sed від 2005 року. Більшість відмінностей нижче стосуються також інших версій BSD sed.

Sed X OS використовує -Eдля ERE та GNU sed -r. -Eє псевдонімом -rу GNU sed (додано в 4.2, не задокументовано до 4.3). Новіші версії FreeBSD та NetBSD sed підтримують і -Eта, і ін -r. OpenBSD sed підтримує тільки -E.

-i ''працює з sed X OS, але не GNU sed. -iпрацює з GNU sed, останніми версіями NetBSD, OpenBSD sed, але не sed X OS. -i -eпрацює з обома, але у випадку FreeBSD sedробить резервну копію вихідного файлу з -eдодаванням до імені файлу (і вам потрібно передати не більше одного виразу sed).

GNU SED інтерпретує керуючі послідовності , як \t, \n, \001, \x01, \w, і \b. Sed X OS і POSIX sed інтерпретують лише \n(але не в замінній частині s).

GNU sed інтерпретує \|, \+і \?в BRE, але sed X OS і POSIX sed не відповідають. \(, \), \{, І \}є POSIX BRE.

GNU sed дозволяє опускати ;або новий рядок раніше, }але sed X OS не робить.

i(вставка), a(додавання) та c(зміна) повинні супроводжуватися зворотною косою рискою та новою лінією в sed X OS та POSIX sed, але не в GNU sed. GNU СЕД додає бракуючий символ нового рядка після тексту , вставлений i, aабо cале OS X в SED не робить. Наприклад sed 1ia, альтернатива GNU sed $'1i\\\na\n'.

Наприклад, printf a|sed -n pдодається новий рядок в sed X OS, але не в GNU sed.

Sed X OS не підтримує I(нечутливі до регістру) або M(багаторядкові) модифікатори. Новіші версії підтримки FreeBSD sed I.

Sed X OS не підтримує -s( --separate), -u( --unbuffered) або -z( --null-data).

Один варіант BSD, який не підтримується GNU sed, - -aце wдодавання до файлу, а не обрізання файлу.

Приклади команд GNU sed, які не працюють з sed X OS:

sed /pattern/,+2d # like `sed '/pattern/{N;N;d;}'`
sed -n 0~3p # like `awk NR%3==0`
sed /pattern/Q # like `awk '/pattern/{exit}1'` or `sed -n '/pattern/,$!p'`
sed 's/\b./\u&/g' # \u converts the next character to uppercase
sed 's/^./\l&/' # \l converts the next character to lowercase
sed -i '1ecat file_to_prepend' file # e executes a shell command
sed -n l0 # 0 disables wrapping

4
-i -eне працює на OSX. Він інтерпретується -eяк суфікс.
Кріс Мартін

3
@ChrisMartin так, у версії OS X -iзавжди потрібен суфікс, навіть якщо порожній рядок. так -i '' -eмає працювати.
waldyrious

@waldyrious Працює лише на OSX.
Кріс Мартін

так, це
вигадка

3
Речення « -i -eпрацює з обома». у Вашій відповіді випливає, що існує кросплатформене рішення. Мабуть, немає.
leondepeon

5

Найкращий спосіб, коли я виявив, що однаковий сценарій працює на Linux і Mac, це:

sed -i.bak -e 's/foo/bar/' -- "${TARGET}" &&
  rm -- "${TARGET}.bak"

Або використовувати perlтам, де це -iпоходить. perl -Tpi -e 's/foo/bar/' -- "$TARGET"
Стефан Шазелас
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.