Рекурсивный поиск и замена в текстовых файлах на 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будет запущено более одного экземпляра.)


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' @

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

13

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

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

perl -pi -w -e 's/SEARCH_FOR/REPLACE_WITH/g;' *.txt

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'

Мне пришлось выполнить экспорт из этого ответа + строка из принятого ответа (я не хотел, чтобы файлы резервных копий создавались)
Лэнс

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 изменят файлы, которые не содержат текст поиска (добавьте новую строку в конец файла), что является подробным.


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

0
find . -type f | xargs sed -i '' 's/string1/string2/g'

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


-3

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


Я так и думал, но нет. При загрузке в 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» , ни один из которых не существует.
Бретт Хейл,

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.