Команда 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' *


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Кажется, не работает
— должным образом


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)


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" путь к файлу


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.


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


3
Это создает в Linux другое имя файла с eдобавленным
— Brice

1
Разбитый, лучше его убрать.
— сорин

Работает на Mac и Linux. В чем проблема с этим решением?
— Ислам Азаб

Нет, он не работает на Mac BSD Sed - он создает файл резервной копии с добавлением 'e' к имени файла.
— Джеспер Гранн Лаурсен
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.