Различия между sed на Mac OSX и другими «стандартными» sed?

61

У меня возникли некоторые проблемы с использованием ответа, предоставленного на этом сайте, на этот вопрос о команде sed, чтобы заменить пустую строку двумя другими строками контента , и она была поднята, если команда sed в Mac OS (10.6.7 для меня ) это отличается. Я не думаю, что это так, но мне было интересно, если другие на этом сайте думали иначе.

Питер Гриль
источник

Ответы:

43

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

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

Что касается sed, обратитесь к спецификации sed Single Unix для получения информации о минимуме, который должна поддерживать каждая система, к странице руководства вашей системы о том, что поддерживает ваша реализация, и к руководству по 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 -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
Стефан
60

OS X в настоящее время поставляется с операционной системой FreeBSD 2005 года. Большинство различий ниже также применимы к другим версиям BSD sed.

OS X использует sed -Eдля ERE и GNU sed использует -r. -Eпсевдоним для -rв GNU sed (добавлено в 4.2, не документировано до 4.3). Более новые версии FreeBSD и NetBSD sed поддерживают -Eи -r. OpenBSD sed поддерживает только -E.

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

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

GNU sed интерпретирует \|, \+и \?в BRE, но OS X sed и POSIX sed не делают. \(, \), \{, И \}являются POSIX BRE.

GNU sed позволяет пропустить ;или новую строку раньше, }а OS X - нет.

i(вставка), a(добавление) и c(изменение) должны сопровождаться обратной косой чертой и новой строкой в ​​OSD sed и POSIX sed, но не в GNU sed. GNU СЭД добавляет недостающий символ новой строки после текста , вставленный i, aили cно OS X в SED не делает. Например, sed 1iaGNU альтернатива sed $'1i\\\na\n'.

Например, printf a|sed -n pдобавляет новую строку в OS X sed, но не в GNU sed.

OS X sed не поддерживает I(без учета регистра) или M(многострочные) модификаторы. Более новые версии поддержки FreeBSD sed I.

OS X sed не поддерживает -s( --separate), -u( --unbuffered) или -z( --null-data).

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

Примеры команд GNU sed, которые не работают с sed OS X:

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
LRI
источник
4
-i -eне работает на OSX. Это -eкак суффикс.
Крис Мартин
3
@ChrisMartin да, в версии для OS X -iвсегда требуется суффикс, даже если пустая строка. так -i '' -eдолжно работать.
Waldyrious
@waldyrious Работает только на OSX.
Крис Мартин
да, это причуды этой версии :)
Waldyrious
3
Предложение « -i -eработает с обоими». в вашем ответе предполагается, что есть кроссплатформенное решение. Видимо нет.
leondepeon
5

Я обнаружил, что лучший способ работы одного и того же скрипта на Linux и Mac:

sed -i.bak -e 's/foo/bar/' -- "${TARGET}" &&
  rm -- "${TARGET}.bak"
vikrantt
источник
Или используйте perlоткуда это -i. perl -Tpi -e 's/foo/bar/' -- "$TARGET"
Стефан