Команда sed с опцией -i не работает на Mac, но работает на Linux - PullRequest
249 голосов
/ 22 ноября 2010

Я успешно использовал следующую команду sed для поиска / замены текста в Linux:

sed -i 's/old_link/new_link/g' *

Тем не менее, когда я пробую это на моем Mac OS X, я получаю:

"команда c ожидает \, за которой следует текст"

Я думал, что на моем Mac установлена ​​обычная оболочка BASH.Что случилось?

РЕДАКТИРОВАТЬ:

Согласно @High Performance, это связано с тем, что Mac sed имеет другой (BSD) вкус, поэтому мой вопрос будетследовательно, как мне повторить эту команду в BSD sed?

РЕДАКТИРОВАТЬ:

Вот фактический пример, который вызывает это:

sed -i 's/hello/gbye/g' *

Ответы [ 11 ]

338 голосов
/ 22 ноября 2010

Если вы используете опцию -i, вам необходимо указать расширение для резервных копий.

Если у вас есть:

File1.txt
File2.cfg

Команда (обратите внимание на отсутствие пробела между -i и '' и -e для работы в новых версиях Mac и GNU):

sed -i'.original' -e 's/old_link/new_link/g' *

Создайте 2 файла резервной копии, например:

File1.txt.original
File2.cfg.original

Тамне является переносимым способом избежать создания файлов резервных копий, потому что невозможно найти сочетание команд sed, которое работает во всех случаях:

  • sed -i -e ... - не работает в OS X, поскольку создает -e резервные копии
  • sed -i'' -e ... - не работает в OS X 10.6, но работает в 10.9 +
  • sed -i '' -e ... - не работает в GNU

Примечание Учитывая, что на всех платформах не работает команда sed, вы можете попробовать использовать другую команду для достижения того же результата.

Например, perl -i -pe's/old_link/new_link/g' *

51 голосов
/ 22 ноября 2010

Я полагаю, что в OS X при использовании -i расширение для файлов резервных копий требуется .Попробуйте:

sed -i .bak 's/hello/gbye/g' *

Используя GNU sed расширение необязательно .

48 голосов
/ 11 февраля 2013

Работает как с GNU, так и с BSD версиями sed:

sed -i'' -e 's/old_link/new_link/g' *

или с резервной копией:

sed -i'.bak' -e 's/old_link/new_link/g' *

Обратите внимание на отсутствие пробела после опции -i(Необходимо для GNU sed)

24 голосов
/ 01 января 2017

Была такая же проблема в Mac и решена с помощью brew:

brew install gnu-sed

и используйте в качестве

gsed SED_COMMAND

, вы также можете установить sed в качестве псевдонима дляgsed (если хотите):

alias sed=gsed
17 голосов
/ 24 апреля 2012

Или вы можете установить GNU-версию sed на вашем Mac под названием gsed и использовать ее с использованием стандартного синтаксиса Linux.

Для этого установите gsed, используя порты (если у вас его нет, получите http://www.macports.org/), запустив sudo port install gsed. Затем вы можете запустить sed -i 's/old_link/new_link/g' *

8 голосов
/ 28 августа 2012

Ответ Синетриса верен, но я использую это с командой find, чтобы более точно определить, какие файлы я хочу изменить. В целом это должно работать (проверено на osx /bin/bash):

find . -name "*.smth" -exec sed -i '' 's/text1/text2/g' {} \;

В общем случае использование sed без find в сложных проектах менее эффективно.

8 голосов
/ 22 ноября 2010

Ваш Mac действительно запускает оболочку BASH, но это больше вопрос того, с какой реализацией sed вы имеете дело. На Mac Sed происходит из BSD и немного отличается от Sed, который вы можете найти на типичной Linux-системе. Я предлагаю вам man sed.

1 голос
/ 06 июня 2017

Вот как применить переменные окружения к файлу шаблона (нет необходимости в резервном копировании).

1. Создайте шаблон с {{FOO}} для последующей замены.

echo "Hello {{FOO}}" > foo.conf.tmpl

2. Замените {{FOO}} переменной FOO и выведите в новый файл foo.conf

FOO="world" && sed -e "s/{{FOO}}/$FOO/g" foo.conf.tmpl > foo.conf

Работает как macOS 10.12.4 и Ubuntu 14.04.5

0 голосов
/ 21 ноября 2018

Я создал функцию для обработки sed разницы между MacOS (протестировано на MacOS 10.12) и другими ОС:

OS=`uname`
# $(replace_in_file pattern file)
function replace_in_file() {
    if [ "$OS" = 'Darwin' ]; then
        # for MacOS
        sed -i '' -e "$1" "$2"
    else
        # for Linux and Windows
        sed -i'' -e "$1" "$2"
    fi
}

Использование:

$(replace_in_file 's,MASTER_HOST.*,MASTER_HOST='"$MASTER_IP"',' "./mysql/.env")

Где:

, - это разделитель

's,MASTER_HOST.*,MASTER_HOST='"$MASTER_IP"',' - это шаблон

"./mysql/.env" - это путь к файлу

0 голосов
/ 04 июня 2017

Как показывают другие ответы, не существует способа использовать sed переносимым образом в OS X и Linux без создания файлов резервных копий. Таким образом, я вместо этого использовал этот однострочный Ruby:

ruby -pi -e "sub(/ $/, '')" ./config/locales/*.yml

В моем случае мне нужно было вызвать его из задачи rake (т.е. внутри скрипта Ruby), поэтому я использовал этот дополнительный уровень цитирования:

sh %q{ruby -pi -e "sub(/ $/, '')" ./config/locales/*.yml}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...