команда 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 ... - не працює в ГНУ

Примітка. Враховуючи те, що на всіх платформах не працює команда sed, ви можете спробувати використати іншу команду для досягнення того ж результату.

Наприклад, perl -i -pe's/old_link/new_link/g' *


4
У мене було те саме питання. Дякую за це рішення. Але там, де я спробував з «man sed» знайти опис '-i', нічого про використання -i '' для ігнорування резервних копій немає. Це моя перша провина. По-друге, коли з'являється помилка "команда очікує \ за нею текст", чому вона не каже нам безпосередньо, що очікує резервного імені для параметра "-i" !! ?? Таке трапляється скрізь: ви отримуєте помилку, але не причину помилки, тоді шукаєте посібник, який нічого не пояснює. Потім ви google це, щоб знайти когось іншого, також має ту ж проблему. Я маю на увазі, чому б не навести приклад у посібнику?
lukmac

або скажіть нам, чому помилка виникає замість лише повідомлення без інформації, що сталася помилка. Це пропозиція для всіх виробників інструментів, якщо вони коли-небудь зможуть прочитати цей коментар.
lukmac

5
@lukmac Наскільки ви sedможете сказати, ви DID постачаєте резервний суфікс. Резервний суфікс є s/old_link/new_link/g. Наступним аргументом після цього повинні бути команди редагування. Оскільки він інтерпретував команди як резервне ім'я, тоді він взяв перше ім'я файлу як команди редагування, але вони не були дійсними.
Вармар

2
Чи завжди це буде проблемою? Чи існує якийсь спосіб, щоб Apple могла створити обхідний / пакетний GNU sed з OSX? Або не вдалося підтримати GNU sed sed -i '' -e ...?
вибухнув

5
sed -i'' -eздається, не працює так, як очікувалося на Mac 10,14
MoOx


55

Це працює з GNU і BSD версіями sed:

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

або з резервною копією:

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

Зверніть увагу на відсутність місця після -iопції! (Необхідно для sed GNU)


7
Перший не працює на OSX (я тільки тестував його 10.6.8)
marcin

4
Для мене в OS X (10.10.3) перший створений резервні файли з суфіксом -e. Не добре. Друге - це єдине, що працювало для мене послідовно між Ubuntu та OS X. Хоча я не хотів резервних файлів, тому мені довелося запускати rmкоманду відразу після її видалення.
Брендан

1
Перший рядок слід переписати з пробілом для роботи 10.10: sed -i'' ...=>sed -i '' ...
Даніель Джомф

3
@DanielJomphe Але додавання цього простору не працює на седі GNU
Бріс,

1
@marcin перший працює для мене також на OSX 10.11.2. Єдине, що він створює файл резервної копії, який потрібно потім видалити. Друге виглядає краще, тому що нам не доведеться з'ясовувати назву файлу пізніше.
vikas027

41

Мав ту ж проблему в Mac і вирішив її за допомогою brew:

brew install gnu-sed

і використовувати як

gsed SED_COMMAND

Ви можете також встановити sedяк псевдонім gsed(якщо хочете):

alias sed=gsed

3
Чому ви дали абсолютно таку ж відповідь, як Охад Кравчик ?
gniourf_gniourf

1
встановити псевдонім, як це, не є чудовою ідеєю
SantaXL

1
Замість псевдоніму, як рекомендується на відповідній сторінці приготування, додайте його до шляху: PATH = "$ (brew - префікс) / 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
.. або якщо ви використовуєте домашню мову, тоді встановітьgnu-sed
Судар

1
Дякую @Sudar, подвійний палець!
Ендрю Лебедь

9

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


3
Дякую за те, що ми вказали на проблему BSD. Але я досить неграмотний і мені просто потрібно швидко виправити свою команду - швидкий погляд на людину нічого мені не каже
Ярін

5
@Ярин - ні, і якщо я швидко погляну на людину sed, це теж нічого не скаже. Спробуйте довший погляд.
Високопродуктивна марка

21
Більшість відповідей ТА поховані десь у людині, але це те, що ТА - це зайняті люди, яким потрібні відповіді від розумних людей
Ярін

9

Відповідь Сінетріса правильна, але я використовую цю findкоманду, щоб бути більш конкретним щодо того, які файли я хочу змінити. Загалом це має працювати (тестується на osx /bin/bash):

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

Загалом, коли використання sedбез findскладних проектів є менш ефективним.


-execдуже добре! Мені просто цікаво, чи насправді потрібна коса риса
Ye Liu,

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
Зламаний, краще зняти.
sorin

Він працює на Mac та Linux. У чому полягає проблема з цим рішенням?
Іслам

Ні, він не працює на Mac BSD Sed - він створив би резервну копію з "e", доданою до імені файлу.
Jesper Grann Laursen
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.