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

219

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

11 ответов

297
Лучший ответ

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

  • 3
    Я была такая же проблема. Спасибо за это решение. Но там, где я пытался с помощью 'man sed' найти описание '-i', ничего не было с помощью -i '', чтобы игнорировать резервные копии. Это моя первая вина. Во-вторых, когда появляется ошибка «команда ожидает \ с последующим текстом», почему она прямо не говорит нам, что ожидает имя резервной копии для опции «-i» !! ?? Такое случается повсюду: вы получаете ошибку, но не объясняете ее, а затем ищете руководство, которое ничего не объясняет. Затем вы Google, чтобы найти кого-то еще также имеет ту же проблему. Я имею в виду, почему бы не привести пример в руководстве?
  • 0
    или скажите нам, почему существует ошибка, а не только информационное сообщение о том, что происходит ошибка. Это предложение для всех производителей инструментов, если они когда-либо смогут прочитать этот комментарий.
Показать ещё 3 комментария
46

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

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

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

  • 0
    спасибо - Синетрис просто победил тебя
37

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

  • 6
    Первый не работает на OSX (я только что протестировал его на 10.6.8)
  • 5
    У меня 1й работает на 10.9.2
Показать ещё 5 комментариев
18

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

brew install gnu-sed

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

gsed SED_COMMAND

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

alias sed=gsed
14

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

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

  • 21
    .. или если вы используете homebrew, то установите gnu-sed
  • 1
    Спасибо @Sudar, двойной палец вверх!
8

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

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

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

  • 0
    -exec очень приятно! Мне просто интересно, нужен ли в конце слеш
  • 2
    @YeLiu: без \ , то ; интерпретируется оболочкой, когда я пытался
7

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

  • 3
    Спасибо за указание на проблему BSD - Но я довольно неграмотный и мне просто нужно быстро исправить мою команду - быстрый взгляд на человека ничего не говорит мне
  • 5
    @ Ярин - нет, и если я взгляну на человека, это тоже ничего тебе не скажет. Попробуйте длинный взгляд.
Показать ещё 1 комментарий
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 в разницу между 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

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

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

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

sh %q{ruby -pi -e "sub(/ $/, '')" ./config/locales/*.yml}
-1
sed -ie 's/old_link/new_link/g' *

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

  • 3
    Это создает в Linux другое имя файла с добавленной e
  • 1
    Разбитый, лучше его убрать.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню