Я ничего не знаю о Sed, но мне нужна эта команда (которая отлично работает на Ubuntu) для работы с Mac OSX:
sed -i "/ $domain .*#drupalpro/d" /etc/hosts
Я получаю:
sed: 1: "/etc/hosts": extra characters at the end of h command
Я ничего не знаю о Sed, но мне нужна эта команда (которая отлично работает на Ubuntu) для работы с Mac OSX:
sed -i "/ $domain .*#drupalpro/d" /etc/hosts
Я получаю:
sed: 1: "/etc/hosts": extra characters at the end of h command
Ubuntu поставляется с GNU sed
, где суффикс для опции -i
не является обязательным. OS X поставляется с BSD sed
, где суффикс является обязательным. Попробуйте sed -i ''
Чтобы дополнить микротерий полезный, точный ответ:
TL;DR:
Эквивалент этого 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
, который выполняет обновление на месте [1]
его входных файлов принимает аргумент option, который указывает, какой суффикс (расширение имени файла) используется для файла резервной копии обновляемого файла.
Например, в обеих реализациях сохраняется исходный файл 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
это обязательный параметр, приведенный выше синтаксис работает с обеими реализациями, потому что непосредственно примыкает аргумент option (.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 script (команда) - теперь интерпретируется как суффикс, а слово file
интерпретируется как script.
Интерпретация такого слова, как script, приводит к неясному сообщению об ошибке, например,
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] Строго говоря, временный файл создается за кулисами, который затем заменяет исходный файл; этот подход может быть проблематичным: см. нижнюю половину этого answer.
Человек - ваш друг.
-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 вы можете использовать версию sed для sed: gsed
.
# if using brew
brew install gnu-sed
#if using ports
sudo port install gsed
Затем, если ваш script должен быть портативным, в зависимости от вашей ОС вы можете определить, какую команду использовать.
SED=sed
unamestr=`uname`
if [[ "$unamestr" == "Darwin" ]] ; then
SED=gsed
type $SED >/dev/null 2>&1 || {
echo >&2 "$SED it not installed. Try: brew install gnu-sed" ;
exit 1;
}
fi
# here your sed command, e.g.:
$SED -i "/ $domain .*#drupalpro/d" /etc/hosts