Команда sed с опцией -i не работает на Mac, но работает в Linux

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

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

Однако, когда я пытаюсь использовать его на Mac OS X, я получаю:

"команда c ожидает\с последующим текстом

Я думал, что мой Mac работает с обычной оболочкой BASH. Что?

EDIT:

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

EDIT:

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

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

Ответ 1

Если вы используете опцию -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' *

Ответ 2

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

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

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

Ответ 3

Это работает как с 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)

Ответ 4

Имел ту же проблему в Mac и решил ее с помощью brew:

brew install gnu-sed

и использовать как

gsed SED_COMMAND

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

alias sed=gsed

Ответ 5

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

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

Ответ 6

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

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

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

Ответ 7

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

Ответ 8

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

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

Ответ 9

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

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

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

sh %q{ruby -pi -e "sub(/ $/, '')" ./config/locales/*.yml}

Ответ 10

Я создал функцию для обработки 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" - это путь к файлу

Ответ 11

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

Работает как на BSD, так и на Linux