Рекурсивный поиск и замена в текстовых файлах на Mac и Linux

128

В оболочке Linux следующая команда будет рекурсивно искать и заменять все экземпляры «this» на «that» (передо мной нет оболочки Linux, но она должна работать).

find . -name "*.txt" -print | xargs sed -i 's/this/that/g'

Как будет выглядеть аналогичная команда в OSX?

разъем
источник
Вероятно, следует перенести на, apple.stackexchange.comпоскольку он недостаточно универсален для Linux и всех разработчиков.
AlikElzin-kilaka

Ответы:

246

OS X использует сочетание инструментов BSD и GNU, поэтому лучше всегда проверять документацию (хотя у меня она lessдаже не соответствовала справочной странице OS X):

https://web.archive.org/web/20170808213955/https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man1/sed.1.html

sed принимает аргумент после -iкак расширение для резервных копий. Если -i ''нет резервных копий, укажите пустую строку ( ).

Следующее должно сделать:

LC_ALL=C find . -type f -name '*.txt' -exec sed -i '' s/this/that/ {} +

Это -type fпросто хорошая практика; sed будет жаловаться, если вы дадите ему каталог или около того. -execпредпочтительнее xargs; вам не нужно беспокоиться -print0ни о чем. Значок {} +в конце означает, что findвсе результаты будут добавлены в качестве аргументов к одному экземпляру вызываемой команды, вместо того, чтобы повторно запускать ее для каждого результата. (Одно исключение - когда максимальное количество аргументов командной строки, разрешенное ОС, нарушено; в этом случае findбудет запущено более одного экземпляра.)

TaylanUB
источник
2
Мое "this" в этой замене содержит косую черту (localhost / site) - я заменяю части URL-адреса в файле .html .... как мне сделать такую ​​замену. Я попытался поставить двойные кавычки, но это не удалось.
Тимоти Т.
6
Sed синтаксис позволяет использовать практически любой символ вместо косые черты, например , вы можете использовать %символ: sed "s%localhost/site%blah/blah%". Другой альтернативой является обратной косой черты избежать разделитель: sed "s/localhost\/site/blah\/blah/".
TaylanUB
Спасибо, позвольте мне попробовать. Однако я попытался использовать {} для разделения косой черты, но все равно получил ошибку ...
Тимоти Т.
16
Кто-нибудь еще получает illegal byte sequenceошибку? если да, попробуйте: LC_ALL=C find . -type f -name '*.txt' -exec sed -i '' s/this/that/ {} +у меня сработало.
ColdTuna
10
Это заменит только одно событие на файл, используется /gдля нескольких валют, напримерLC_ALL=C find . -type f -exec sed -i '' s/search/replace/g {} +
jamesjara
154

Для Mac более похожий подход будет следующим:

find . -name '*.txt' -print0 | xargs -0 sed -i "" "s/form/forms/g"
Гайбраш Трипвуд
источник
10
Хотел бы я голосовать за это каждый раз, когда возвращаюсь к нему и использую его. Сейчас было бы +15, легко.
Droogans
У меня почему-то не работает. Ничего не делает. Я внутри папки form360, и я пытаюсь изменить все экземпляры строк с именем easyform на form360, я запускаю следующую команду:find . -name '*.php' -print0 | xargs -0 sed -i "" "s/easyform/form360/g"
Andres Ramos
2
для меня это должен быть правильный ответ. Это единственное, что у меня сработало.
Nosequeldeebee 01
1
-print0 | xargs -0 не работает на моем Mac, если имя файла содержит пробел.
user2807219
1
sed:.: редактирование на месте работает только для обычных файлов
codelapper 02
14

В качестве альтернативного решения я использую это на Mac OSX 10.7.5.

grep -ilr 'old-word' * | xargs -I@ sed -i '' 's/old-word/new-word/g' @

Кредит принадлежит: ответ Тодда Сезера

Мацей Гурбан
источник
Этот хорошо работает! Другие скрипты добавляют дополнительный конец строки в некоторых случаях на OSX! Большое спасибо!
Себастьян Филион
14

В Mac OSX 10.11.5 это отлично работает:

grep -rli 'old-word' * | xargs -I@ sed -i '' 's/old-word/new-word/g' @
madx
источник
xargs -I @ sed -i '' 's / old-word / new-word / g' @ работал у меня после того, как попробовал так много других неработающих предложений. Спасибо!
DrB
13

Ничего из вышеперечисленного не работает на OSX.

Сделайте следующее:

perl -pi -w -e 's/SEARCH_FOR/REPLACE_WITH/g;' *.txt
eb80
источник
1
как убрать '/', если SEARCH_FOR и REPLACE_WITH - пути?
rraallvv
Используйте другой разделитель. Если вы используете пути, подойдет двоеточие или вертикальная черта. 's | SEARCH | REPLACE | g', например. Мы используем фигурные скобки, например {SEARCH} {REPLACE}.
dannysauer
1
Дито вопрос, не пытаюсь на Mac - но, похоже, возникает ошибка? Например, мой путь интерпретируется как файл? -bash: localhost / nohost: Нет такого файла или каталога
Тимоти Т.
это не проходит через папки глубоко. Только один уровень.
Сергей Романов
Подробнее об этой команде читайте на сайте lifehacker.com/5810026/…
kuzdu
7

Версия, которая работает как в Linux, так и в Mac OS X (путем добавления -eпереключателя в sed):

export LC_CTYPE=C LANG=C
find . -name '*.txt' -print0 | xargs -0 sed -i -e 's/this/that/g'
VROC
источник
Мне пришлось выполнить экспорт из этого ответа + строка из принятого ответа (я не хотел, чтобы файлы резервных копий создавались)
Лэнс
2
чтобы export LC_CTYPE=C && export LANG=C
устранить
НИКОГДА НЕ ЗАПУСКАЙТЕ это с '*' вместо '* .filetype', как я сделал, если вы используете Git. Или вы можете попрощаться со всеми своими неопубликованными работами.
Сергей
1
Версия команды sed для mac требует "" после -i, поэтому этот ответ неверен
Дж. Хаксли
2

Всякий раз, когда я набираю эту команду, мне всегда кажется, что я ее пропускаю или забываю флаг. Я создал Gist на github на основе ответа TaylanUB, который выполняет глобальную замену поиска из текущего каталога. Это специфично для Mac OSX.

https://gist.github.com/nateflink/9056302

Это приятно, потому что теперь я просто открываю терминал и копирую:

curl -s https://gist.github.com/nateflink/9056302/raw/findreplaceosx.sh | bash -s "find-a-url.com" "replace-a-url.com"

Вы можете получить некоторые странные ошибки последовательности байтов, поэтому вот полный код:

#!/bin/bash
#By Nate Flink

#Invoke on the terminal like this
#curl -s https://gist.github.com/nateflink/9056302/raw/findreplaceosx.sh | bash -s "find-a-url.com" "replace-a-url.com"

if [ -z "$1" ] || [ -z "$2" ]; then
  echo "Usage: ./$0 [find string] [replace string]"
  exit 1
fi

FIND=$1
REPLACE=$2

#needed for byte sequence error in ascii to utf conversion on OSX
export LC_CTYPE=C;
export LANG=C;

#sed -i "" is needed by the osx version of sed (instead of sed -i)
find . -type f -exec sed -i "" "s|${FIND}|${REPLACE}|g" {} +
exit 0
Нейт Флинк
источник
2

Это моя работоспособная. в Mac OS X 10.10.4

grep -e 'this' -rl . | xargs sed -i '' 's/this/that/g'

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

NoteCode
источник
2

Если вы используете терминал zsh, вы можете использовать магию подстановочных знаков:

sed -i "" "s/search/high-replace/g" *.txt

Наставник
источник
1

Я использовал этот формат - но ... Я обнаружил, что мне нужно запускать его три или более раз, чтобы заставить его фактически изменить каждый экземпляр, который я нашел чрезвычайно странным. При однократном запуске некоторые из них будут изменены в каждом файле, но не все. Выполнение одной и той же строки два-четыре раза приведет к перехвату всех экземпляров.

find . -type f -name '*.txt' -exec sed -i '' s/thistext/newtext/ {} +
Эмма
источник
Вам нужно было запустить эту команду несколько раз g, потому что вашему регулярному выражению sed нужен a в конце, иначе он заменяет только первое вхождение thistextв строке. Итак, ваше регулярное выражение должно бытьs/thistext/newtext/g
Les Nightingill
0

https://bitbucket.org/masonicboom/serp - это утилита go (то есть кроссплатформенная), протестированная на OSX, которая выполняет рекурсивный поиск и замену текста в файлах в заданном каталоге и подтверждает каждую замену. Он новый, так что может глючить.

Использование выглядит так:

$ ls test
a  d  d2 z
$ cat test/z
hi
$ ./serp --root test --search hi --replace bye --pattern "*"                         
test/z: replace hi with bye? (y/[n]) y
$ cat test/z
bye
user4425237
источник
0
find . -type f | xargs sed -i '' 's/string1/string2/g'

Обратитесь сюда для получения дополнительной информации.

user2725109
источник
-3

Команда в OSX должна быть точно такой же, как и в Unix с красивым пользовательским интерфейсом.

clops
источник
Я так и думал, но нет. При загрузке в sed он ставит ./ перед файлами, поэтому sed жалуется на «неверный код команды». Может, я просто устал ;-)
Джек
@JacobusR, вырежьте и вставьте из своего терминала OSX - вы, должно быть, вводите что-то немного другое.
Гленн Джекман
3
Вы можете захотеть -print0добавлены в findфлагах и -0на xargsфлагах.
jmtd
Вы также можете просто использовать -exec sed -i s/this/that/g {} \+вместо -printи xargs
Мариан
@JacobusR - это работает, даже если есть путь в начале ./. Однако, если в имени файла есть пробел, скажем «./jacobus \ R.txt», при использовании xargsможет отображаться разделенный пробелами «./jacobus» как файл для перехода sed, а затем с «R.txt» , ни один из которых не существует.
Бретт Хейл,
-4

можно просто сказать $ PWD вместо "."

Сэмюэл Девлин
источник