Команда sed с опцией -i (редактирование на месте) отлично работает на Ubuntu, но не на Mac
Я ничего не знаю о Sed, но мне нужна эта команда (которая прекрасно работает в Ubuntu) для работы на Mac OSX:
sed -i "/ $domain .*#drupalpro/d" /etc/hosts
Я собираюсь:
sed: 1: "/etc/hosts": extra characters at the end of h command
4 ответа
Ubuntu поставляется с GNU sed
где суффикс для -i
опция не обязательна. OS X поставляется с BSD sed
где суффикс обязателен. Пытаться sed -i ''
В дополнение к полезному ответу микротериона:
- с портативным решением
- с исходной информацией
тл; др:
Эквивалент этого GNU sed
(стандарт в большинстве дистрибутивов Linux):
sed -i 's/foo/bar/' file
это BSD/ MacOS sed
команда:
sed -i '' 's/foo/bar/' file # Note the '' as a *separate argument*
С BSD/macOS sed
следующие команды не работают вообще или не работают так, как задумано:
sed -i 's/foo/bar/' file # Breaks; script is misinterpreted as backup-file suffix
sed -i'' 's/foo/bar/' file # Ditto
sed -i -e 's/foo/bar/' file # -e is misinterpreted as backup-file suffix
Для обсуждения всех различий между GNU sed
и BSD/macOS sed
, посмотрите этот мой ответ.
Портативный подход:
Примечание: Portable здесь означает, что команда работает с обеими реализациями, которые обсуждались. Он не является переносимым в смысле POSIX, потому что -i
опция не совместима с POSIX.
# Works with both GNU and BSD/macOS Sed, due to a *non-empty* option-argument:
# Create a backup file *temporarily* and remove it on success.
sed -i.bak 's/foo/bar/' file && rm file.bak
Для объяснения см. Ниже; альтернативные решения, в том числе POSIX-совместимые, см. в этом моем ответе.
Исходная информация
В GNU sed
(стандартно для большинства дистрибутивов Linux) и BSD/macOS sed
, -i
option, который выполняет обновление на месте [1] своих входных файлов, принимает параметр-аргумент, который указывает, какой суффикс (расширение имени файла) использовать для файла резервной копии обновляемого файла.
Например, в обеих реализациях следующее сохраняет исходный файл, file
в качестве резервного файла file.bak
:
sed -i.bak 's/foo/bar/' file # Keep original as 'file.bak'; NO SPACE between -i and .bak
Хотя с GNU sed
аргумент суффикса является необязательным, тогда как для BSD/macOS sed
обязательно, приведенный выше синтаксис работает с обеими реализациями, поскольку непосредственно примыкает к параметру-аргументу ( .bak
) к варианту ( -i
) - -i.bak
в отличие от -i .bak
- работает как необязательный и обязательный параметр-аргумент:
- Синтаксис
-i.bak
это единственная форма, которая работает для необязательного параметра-аргумента. - Синтаксис
-i.bak
также работает как обязательный параметр-аргумент, как альтернатива-i .bak
т.е. указав опцию и ее аргумент отдельно.
Отсутствие указания суффикса - что часто имеет место - означает, что файл резервной копии не должен храниться, и именно здесь возникает несовместимость:
С GNU
sed
не указывать суффикс означает просто-i
само собой.С BSD/macOS
sed
не указание суффикса означает указание пустой строки в качестве суффикса - обязательно - и по техническим причинам пустая строка может быть передана только как отдельный аргумент:-i ''
не-i''
,
-i''
не работает, потому что sed
это неотличимо от всего -i
потому что оболочка эффективно удаляет пустые кавычки (она объединяет -i
а также ''
и удаляет кавычки с синтаксической функцией), и просто проходит -i
в обоих случаях.
С (эффективно) просто -i
указан, это следующий аргумент, который интерпретируется как опция-аргумент:
sed -i 's/foo/bar/' file # BREAKS with BSD/macOS Sed
's/foo/bar/'
- предназначен для сценария (команды) Sed - теперь интерпретируется как суффикс, так и слово file
интерпретируется как сценарий.
Интерпретация такого слова, как сценарий, приводит к неясному сообщению об ошибке, такому как sed: 1: "file": invalid command code f
,
поскольку f
интерпретируется как команда Sed (функция).
Аналогично с:
sed -i -e 's/foo/bar/' file # CREATES BACKUP FILE 'file-e'
-e
интерпретируется как суффиксный аргумент, а НЕ как Sed -e
опция (которая может использоваться для указания нескольких команд, если это необходимо).
В результате вместо сохранения резервной копии вы получаете файл резервной копии с суффиксом -e
,
То, что эта команда не работает должным образом, менее очевидно, потому что обновление на месте происходит успешно, учитывая, что синтаксическое требование аргумента суффикса удовлетворяется -e
аргумент.
То, что случайное создание этих файлов резервных копий легко остается незамеченным, является наиболее вероятным объяснением неправильного ответа Crt и этого неправильного ответа на аналогичный вопрос, получивший так много голосов "за" (на момент написания статьи).
[1] Строго говоря, временный файл создается за кулисами, который затем заменяет оригинальный файл; такой подход может быть проблематичным: см. нижнюю половину моего ответа.
Человек твой друг.
OS X
-i extension
Edit files in-place, saving backups with the specified extension.
If a zero-length extension is given, no backup will be saved. It
is not recommended to give a zero-length extension when in-place
editing files, as you risk corruption or partial content in situ-
ations where disk space is exhausted, etc.
В OS X вы можете использовать GNU-версию sed: gsed
,
# if using brew
brew install gnu-sed
#if using ports
sudo port install gsed
Затем, если ваш скрипт должен быть переносимым, в зависимости от вашей ОС вы можете определить, какую команду использовать.
SED=sed
unamestr=`uname`
if [[ "$unamestr" == "Darwin" ]] ; then
SED=gsed
type $SED >/dev/null 2>&1 || {
echo >&2 "$SED it's not installed. Try: brew install gnu-sed" ;
exit 1;
}
fi
# here your sed command, e.g.:
$SED -i "/ $domain .*#drupalpro/d" /etc/hosts