Sed, который работает как на Mac (BSD), так и на Linux
Есть ли вызов sed
todo in-place редактирования без резервных копий, который работает как на Linux, так и на Mac? В то время как BSD sed
, поставляемый с OS X, кажется, нуждается в sed -i '' …
, дистрибутивы GNU sed
Linux обычно поставляются с интерпретацией кавычек как пустого имени входного файла (вместо расширения для резервного копирования) и вместо этого нуждается sed -i …
.
Есть ли какой-либо синтаксис командной строки, который работает с обоими вариантами, поэтому я могу использовать тот же script в обеих системах?
Ответы
Ответ 1
Если вы действительно хотите просто использовать sed -i
"простым" способом, следующее работает и на GNU, и на BSD/Mac sed
:
sed -i.bak 's/foo/bar/' filename
Обратите внимание на отсутствие места и точки.
Доказательство:
# GNU sed
% sed --version | head -1
GNU sed version 4.2.1
% echo 'foo' > file
% sed -i.bak 's/foo/bar/' ./file
% ls
file file.bak
% cat ./file
bar
# BSD sed
% sed --version 2>&1 | head -1
sed: illegal option -- -
% echo 'foo' > file
% sed -i.bak 's/foo/bar/' ./file
% ls
file file.bak
% cat ./file
bar
Очевидно, что вы можете просто удалить файлы .bak
.
Ответ 2
Это работает с GNU sed, но не в OS X:
sed -i -e 's/foo/bar/' target.file
sed -i'' -e 's/foo/bar/' target.file
Это работает в OS X, но не в GNU sed:
sed -i '' -e 's/foo/bar/' target.file
На OS X вы
- невозможно использовать
sed -i -e
, поскольку расширение файла резервной копии будет установлено на -e
- не может использовать
sed -i'' -e
по тем же причинам - ему нужно пространство между -i
и ''
.
Ответ 3
В OSX я всегда устанавливаю версию GNU sed через Homebrew, чтобы избежать проблем в сценариях, поскольку большинство сценариев были написаны для версий GNU sed.
brew install gnu-sed --with-default-names
Тогда ваш BSD sed будет заменен на GNU sed.
Кроме того, вы можете установить без имен по умолчанию, но затем:
- Измените
PATH
в соответствии с инструкциями после установки gnu-sed
- Проверьте свои сценарии, чтобы выбрать между
gsed
или sed
в зависимости от вашей системы
Ответ 4
Нет способа заставить его работать.
Одним из способов является использование временного файла, например:
TMP_FILE='mktemp /tmp/config.XXXXXXXXXX'
sed -e "s/abc/def/" some/file > $TMP_FILE
mv $TMP_FILE some/file
Это работает на обоих
Ответ 5
Как Нуфаль Ибрагим спрашивает, почему вы не можете использовать Perl? Любой Mac будет иметь Perl, и существует очень мало дистрибутивов Linux или BSD, которые не включают некоторую версию Perl в базовой системе. Одной из единственных сред, на которых, возможно, не было Perl, был бы BusyBox (который работает как GNU/Linux для -i
, за исключением того, что не может быть указано расширение для резервного копирования).
Как ismail рекомендует
Поскольку perl доступен везде, я просто делаю perl -pi -e s,foo,bar,g target.file
и это похоже на лучшее решение практически в любом случае, чем скрипты, псевдонимы или другие обходные пути для решения основной несовместимости sed -i
между GNU/Linux и BSD/Mac.
Ответ 6
Ответ: Нет.
Первоначально принятый ответ фактически не выполняет то, что запрашивается (как отмечено в комментариях). (Я нашел этот ответ, когда искал причину, по которой file-e
появлялся "случайно" в моих каталогах.)
По-видимому, нет способа заставить sed -i
работать последовательно как на MacOS, так и на Linuces.
Моя рекомендация, для чего это стоит, заключается не в обновлении на месте с помощью sed
(который имеет сложные режимы сбоя), а для создания новых файлов и последующего их переименования. Другими словами: избегайте -i
.
Ответ 7
Параметр -i
не является частью POSIX Sed. Более портативный метод будет
использовать Vim в режиме Ex:
ex -sc '%s/alfa/bravo/|x' file
%
выбрать все строки
s
заменить
x
сохранить и закрыть
Ответ 8
Вот еще одна версия, которая работает на Linux и MacOS без использования eval
и без необходимости удаления файлов резервных копий. Он использует массивы Bash для хранения параметров sed
, что чище, чем при использовании eval
:
# Default case for Linux sed, just use "-i"
sedi=(-i)
case "$(uname)" in
# For macOS, use two parameters
Darwin*) sedi=(-i "")
esac
# Expand the parameters in the actual call to "sed"
sed "${sedi[@]}" -e 's/foo/bar/' target.file
Это не создает файл резервной копии, ни файл с добавленными кавычками.
Ответ 9
Ответ Стив Пауэлла вполне корректен, консультируя страницу MAN для sed на OSX и Linux (Ubuntu 12.04), подчеркивает совместимость внутри "на месте" sed использование в двух операционных системах.
JFYI, не должно быть пробела между -i и любыми кавычками (которые обозначают пустое расширение файла) с использованием версии sed для sed, таким образом
sed Man Man Страница
#Linux
sed -i""
и
команда sed OSX Man
#OSX (notice the space after the '-i' argument)
sed -i ""
Я обошел это в script с помощью команды alias'd и вывода OS-имени " uname" в bash 'if'. Попытка хранить OS-зависимые командные строки в переменных была удалена и пропущена при интерпретации кавычек. Использование " shopt -s expand_aliases" необходимо для расширения/использования псевдонимов, определенных в вашем script. Использование магазина используется здесь.
Ответ 10
Я столкнулся с этой проблемой. Единственным быстрым решением было заменить sed в mac на версию gnu:
brew install gnu-sed
Ответ 11
Если вам нужно сделать sed
на месте в bash
script, и вы НЕ хотите, чтобы на месте результат с .bkp файлами, и у вас есть способ обнаружить os (скажем, используя ostype.sh), - тогда должен работать следующий хак с встроенной оболочкой bash
eval
:
OSTYPE="$(bash ostype.sh)"
cat > myfile.txt <<"EOF"
1111
2222
EOF
if [ "$OSTYPE" == "osx" ]; then
ISED='-i ""'
else # $OSTYPE == linux64
ISED='-i""'
fi
eval sed $ISED 's/2222/bbbb/g' myfile.txt
ls
# GNU and OSX: still only myfile.txt there
cat myfile.txt
# GNU and OSX: both print:
# 1111
# bbbb
# NOTE:
# if you just use `sed $ISED 's/2222/bbbb/g' myfile.txt` without `eval`,
# then you will get a backup file with quotations in the file name,
# - that is, `myfile.txt""`
Ответ 12
Вы можете использовать губку. Sponge - старая программа unix, найденная в пакете moreutils (как в ubuntu, так и, вероятно, в debian, и в homebrew в mac).
Он будет буферизировать все содержимое из канала, дождитесь закрытия канала (вероятно, это значит, что входной файл уже закрыт), а затем перезапишите:
На странице man:
Сводка
sed '...' file | grep '...' | файл губки
Ответ 13
Следующие работы для меня в Linux и OS X:
sed -i' ' <expr> <file>
например. для файла f
, содержащего aaabbaaba
sed -i' ' 's/b/c/g' f
дает aaaccaaca
как на Linux, так и на Mac. Обратите внимание, что есть строка с кавычками, содержащая пробел, без пробела между -i
и строкой. Работают одиночные или двойные кавычки.
В Linux я использую bash
версию 4.3.11 под Ubuntu 14.04.4 и на Mac версии 3.2.57 под OS X 10.11.4 El Capitan (Darwin 15.4.0).
Ответ 14
Ответ от @klickverbot кажется устаревшим.
В эти дни он отлично работает на Linux и OS X, чтобы использовать следующую команду:
sed -i'' -e 's/foo/bar/' file-to-change.txt