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


127

У оболонці Linux наступна команда буде рекурсивно шукати та замінювати всі екземпляри "цього" на "те" (у мене немає оболонки 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 приймає аргумент after -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
Моє "це" у цій заміні містить просунуту косу лінію (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 {} +
валют,

152

Для 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

1
-принт0 | xargs -0 не працює на моєму комп'ютері, коли ім'я файлу містить пробіл.
user2807219

1
sed:.: на місці редагування працює лише для звичайних файлів
codelapper

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 '@ працював для мене після того, як спробував так багато інших непрацюючих пропозицій. Дякую!
ДрБ

13

Жоден із перерахованих вище не працює на OSX.

Зробіть наступне:

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

1
як відшаровувати "/", якщо SEARCH_FOR та REPLACE_WITH - це шляхи?
rraallvv

Використовуйте інший роздільник. Якщо ви використовуєте доріжки, двокрапка або труба спрацює. 's | ПОШУК | ЗАМІНА | g', наприклад. Наші дужки використання, як у {SEARCH} {REPLACE} '.
dannysauer

1
питання dito, спроба його немає на 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'

Мені довелося здійснити експорт з цієї відповіді + рядок із прийнятої відповіді (я не хотів створювати резервні файли)
Lance

2
щоб export LC_CTYPE=C && export LANG=C
усунути

НІКОЛИ НЕ РУБАЙТЕ це за допомогою "*" замість "* .filetype", як я робив, якщо ви використовуєте Git. Або ви можете попрощатися з усіма вашими неопублікованими роботами.
Сергій

1
Версія mac для команди sed вимагає '' після -i, тому ця відповідь неправильна
G Huxley

2

Кожного разу, коли я ввожу цю команду, я, здається, завжди всмоктую її або забуваю прапор. Я створив Gist on 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" "substitu-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'

Вищезгадане використання знахідки змінить файли, які не містять текст пошуку (додайте новий рядок на кінці файлу), який є багатослівним.


2

Якщо ви використовуєте zsh-термінал, ви можете використовувати магію підстановки:

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


1

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

find . -type f -name '*.txt' -exec sed -i '' s/thistext/newtext/ {} +

Вам потрібно було запустити цю команду кілька разів b / c, ваш sedgegege потребує a gв кінці, інакше він замінює лише перше виникнення 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


-3

Команда на OSX повинна бути точно такою ж, як і Unix під симпатичним інтерфейсом.


Я думав стільки ж, але ні. Він ставить ./ перед файлами при подачі на sed, тому sed скаржиться на "недійсний код команди". Можливо, я просто втомився ;-)
Джек

@JacobusR, будь ласка, виріжте і вставте з вашого терміналу OSX - ви повинні вводити щось дещо інше.
glenn jackman

3
Ви можете -print0додати до findпрапорів і -0до xargsпрапорів.
jmtd

Також ви можете просто використовувати -exec sed -i s/this/that/g {} \+замість -printі xargs
Marian

@JacobusR - це працює, навіть якщо є провідна назва шляху. Однак якщо у назві файлу є пробіл, скажімо, "./jacobus \ R.txt", використання xargsможе бачити пробіл "./jacobus" як файл для передачі sed, а потім з "R.txt" , жоден з яких не існує.
Бретт Хейл

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