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

303

Я успешно использовал следующую 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' *
Ярина
источник
1
Это означает, что sedвидит «c» в ваших данных как команду. Вы используете переменную? Пожалуйста, опубликуйте что-то, что более точно отражает фактическую команду и некоторые данные, которые вы обрабатываете. Вы можете получить простую демонстрацию этой ошибки, выполнив echo x | sed c.
Приостановлено до дальнейшего уведомления.
@Dennis, простая команда, приведенная выше, вызывает это, хотя данные, которые он обрабатывает, представляют собой целый веб-сайт (я конвертирую все ссылки на изображения), включая файлы html и css ...
Ярин

Ответы:

397

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

Sinetris
источник
4
Я была такая же проблема. Спасибо за это решение. Но там, где я пытался с помощью 'man sed' найти описание '-i', ничего не было с помощью -i '', чтобы игнорировать резервные копии. Это моя первая вина. Во-вторых, когда появляется ошибка «команда ожидает \ сопровождается текстом», почему она прямо не говорит нам, что ожидает имя резервной копии для опции «-i» !! ?? Такое случается повсюду: вы получаете ошибку, но не объясняете ее, а затем ищете руководство, которое ничего не объясняет. Затем вы Google, чтобы найти кого-то еще также имеет ту же проблему. Я имею в виду, почему бы не привести пример в руководстве?
lukmac
или скажите нам, почему существует ошибка, а не только информационное сообщение о том, что происходит ошибка. Это предложение для всех производителей инструментов, если они когда-либо смогут прочитать этот комментарий.
lukmac
5
@lukmac Насколько я sedмогу судить, вы поставили резервный суффикс. Суффикс резервной копии есть s/old_link/new_link/g. Следующим аргументом после этого должны быть команды редактирования. Поскольку он интерпретировал команды как имя резервной копии, он взял первое имя файла в качестве команд редактирования, но они не были действительными.
Бармар
2
Это всегда будет проблемой? Есть ли какой-нибудь способ, которым Apple может создать обходной путь / пакет GNU sed с OSX? Или GNU sed не поддерживает sed -i '' -e ...?
Блонг
5
sed -i'' -eКажется, не работает
должным образом
64

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

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

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

Приостановлено до дальнейшего уведомления.
источник
55

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

chipiik
источник
7
Первый не работает на OSX (я только что протестировал его на 10.6.8)
marcin
4
Для меня в OS X (10.10.3) первый создал файлы резервных копий с суффиксом -e. Не хорошо. Второй был единственной вещью, которая работала для меня последовательно между Ubuntu и OS X. Я не хотел резервных файлов, поэтому мне пришлось запустить rmкоманду сразу после удаления.
Брендан
1
Первая строка должна быть переписана с пробелом для работы 10.10: sed -i'' ...=>sed -i '' ...
Daniel Jomphe
3
@DanielJomphe Но добавление этого пространства не работает на GNU sed
Брайс,
1
@marcin first работает и для меня на OSX 10.11.2. Единственное, что он создает файл резервной копии, который впоследствии необходимо удалить. Второй выглядит лучше, так как нам не нужно выяснять имя файла позже.
vikas027
41

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

brew install gnu-sed

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

gsed SED_COMMAND

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

alias sed=gsed
Срути Поддутур
источник
3
Почему вы дали точно такой же ответ, как Охад Кравчик ?
gniourf_gniourf
1
установка псевдонима не очень
хорошая
1
Вместо псевдонима, как рекомендуется на соответствующей странице brew, добавьте его в путь: PATH = "$ (brew --prefix) / opt / gnu-sed / libexec / gnubin: $ PATH"
y.luis
24

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

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

Охад Кравчик
источник
24
.. или если вы используете homebrew, то установитеgnu-sed
Sudar
1
Спасибо @Sudar, двойной палец вверх!
Эндрю Свон
9

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

Высокая производительность
источник
3
Спасибо за то, что указали на проблему BSD - Но я довольно неграмотный и мне просто нужно быстро исправить мою команду - быстрый взгляд на человека ничего не говорит мне
Ярин
5
@ Ярин - нет, и если я взгляну на человека, это тоже ничего тебе не скажет. Попробуйте длинный взгляд.
Высокая производительность Марк
21
Большинство SO-ответов похоронены где-то в человеке, но именно так SO-это занятые люди, которым нужны ответы от умных людей
Ярин
9

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

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

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

Лукас
источник
-execэто очень мило! Мне просто интересно, нужен ли в конце слеш
Е. Лю
2
@YeLiu: без \, ;интерпретируемая оболочкой оболочка, когда я пробовал такое
serv-inc
2

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

v.babak
источник
1

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

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.

katopz
источник
0

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

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

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

sh %q{ruby -pi -e "sub(/ $/, '')" ./config/locales/*.yml}
Дэн Кон
источник
-1
sed -ie 's/old_link/new_link/g' *

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

ashokrajar
источник
3
Это создает в Linux другое имя файла с eдобавленным
Brice
1
Разбитый, лучше его убрать.
сорин
Работает на Mac и Linux. В чем проблема с этим решением?
Ислам Азаб
Нет, он не работает на Mac BSD Sed - он создает файл резервной копии с добавлением 'e' к имени файла.
Джеспер Гранн Лаурсен