Лучший способ найти / заменить несколько файлов?

как лучше всего это сделать? Я не воин командной строки, но я подумал, что, возможно, есть способ использовать grep и cat.

Я просто хочу заменить строку, которая встречается в папке и подпапках. как лучше всего это сделать? Я использую Ubuntu, если это важно.


person damon    schedule 09.02.2009    source источник
comment
Просто оставлю эту ссылку прямо здесь: stackoverflow.com/questions/102083/   -  person Ehtesh Choudhury    schedule 07.06.2012


Ответы (6)


find . -type f -print0 | xargs -0 -n 1 sed -i -e 's/from/to/g'

Первая часть - это команда find для поиска файлов, которые вы хотите изменить. Возможно, вам придется изменить это соответствующим образом. Команда xargs берет каждый найденный файл и применяет к нему команду sed. Команда sed берет каждый экземпляр from и заменяет его на to. Это стандартное регулярное выражение, поэтому измените его по своему усмотрению.

Если вы используете svn, будьте осторожны. Ваши .svn-каталоги также будут найдены и заменены. Вы должны исключить их, например, вот так:

find . ! -regex ".*[/]\.svn[/]?.*" -type f -print0 | xargs -0 -n 1 sed -i -e 's/from/to/g'

or

find . -name .svn -prune -o -type f -print0 | xargs -0 -n 1 sed -i -e 's/from/to/g'
person Paul Tomblin    schedule 09.02.2009
comment
не похоже, что эта команда повторяется в подкаталогах. что-то я делаю не так? - person damon; 09.02.2009
comment
Что заставляет вас думать, что он не повторяется в каталогах? - person Paul Tomblin; 09.02.2009
comment
текстовые файлы в подкаталогах не вносят изменений. я хочу, чтобы он сделал следующее: измените вхождения some.ip.address на somewebsite.com во всех подкаталогах. - person damon; 09.02.2009
comment
Замените sed на echo и убедитесь, что он находит все ваши файлы. - person Paul Tomblin; 09.02.2009
comment
Если это изменение показывает, что он находит ваши файлы, значит, ошибка в вашем регулярном выражении. Опубликуйте, что вы используете, в части s / some.ip.address / somewebsite.com / g команды sed. - person Paul Tomblin; 09.02.2009
comment
для части sed я использую: find. -тип f -print0 | xargs -0 -n 1 sed -i -e 's / some. \ ip \ .address / somewebsite \ .com / g' - person damon; 09.02.2009
comment
Попробуй найти. -тип f -print0 | xargs -0 -n 1 grep -l 'some \ .ip \ .address', чтобы узнать, действительно ли он находит ваш IP-адрес. - person Paul Tomblin; 09.02.2009
comment
Также возможно, что у вас старая версия sed, которая не поддерживает -i. - person Paul Tomblin; 09.02.2009
comment
если я посмотрю на команду sed --help, она показывает следующее: -i [СУФФИКС], --in-place [= СУФФИКС] редактировать файлы на месте (делает резервную копию, если предоставлено расширение) - person damon; 09.02.2009
comment
Я нахожусь на Mac (Lion), и мне пришлось добавить пустую строку, чтобы не применять суффикс, например: -i '', иначе он интерпретирует -e как суффикс и переименовывает все файлы. Полный пример: find . -type f -name '*.js' -print0 | xargs -0 -n 1 sed -i '' -e 's/from/to/g' (заменяет во всех файлах javascript). - person Thorsten Lorenz; 04.01.2013

Я приведу еще один пример для людей, использующих ag, Silver Searcher для выполнения операций поиска / замены на нескольких файлы.

Полный пример:

ag -l "search string" | xargs sed -i '' -e 's/from/to/g'

Если мы это разберем, то получим:

# returns a list of files containing matching string
ag -l "search string"

Далее у нас есть:

# consume the list of piped files and prepare to run foregoing command
# for each file delimited by newline
xargs

Наконец, команда замены строки:

# -i '' means edit files in place and the '' means do not create a backup
# -e 's/from/to/g' specifies the command to run, in this case,
# global, search and replace

sed -i '' -e 's/from/to/g'
person doremi    schedule 09.06.2016
comment
У меня это больше не работает. Я все время получаю сообщение об ошибке, которое sed не может прочитать: нет такого файла или каталога - person Lance; 05.11.2019
comment
Вы должны сделать ag -l "text" | xargs -I FILE sed -i 's/from/to/g' FILE - person cy8g3n; 21.02.2020
comment
Мужчина говорит -i[SUFFIX], --in-place[=SUFFIX]: edit files in place (makes backup if SUFFIX supplied). Это означает, что после -i должно быть ag -l "search string" | xargs sed -i -e 's/from/to/g' без значения, иначе я получу ту же ошибку, что и @Lance - person Bastien Adam; 07.01.2021

Как сказал Пол, вы хотите сначала найти файлы, которые хотите отредактировать, а затем отредактировать их. Альтернативой использованию find является использование GNU grep (по умолчанию в Ubuntu), например:

grep -r -l from . | xargs -0 -n 1 sed -i -e 's/from/to/g'

Вы также можете использовать ack-grep (sudo apt-get install ack-grep или посетить http://petdance.com/ack/), если вы знаете, что вам нужен только определенный тип файла, и хотите игнорировать вещи в каталогах управления версиями. например, если вам нужны только текстовые файлы,

ack -l --print0 --text from | xargs -0 -n 1 sed -i -e 's/from/to/g'
# `from` here is an arbitrary commonly occurring keyword

Альтернативой использованию sed является использование perl, который может обрабатывать несколько файлов за одну команду, например,

grep -r -l from . | xargs perl -pi.bak -e 's/from/to/g'

Здесь perl предлагается отредактировать на месте, сначала создав файл .bak.

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

person Emil Sit    schedule 09.02.2009
comment
Вы можете избежать использования каталогов управления версиями в find с помощью команды -prune. Например найти. -name RCS -prune -o -type f -print0 - person Paul Tomblin; 09.02.2009
comment
Верно, хотя для того, чтобы иметь такой инструмент, как ack, потребуется меньше мозгов, чтобы справиться с этим за вас. - person Emil Sit; 10.02.2009
comment
ack также принимает параметр --print0 для использования null в качестве разделителя между именами файлов, поэтому ваша команда ack будет выглядеть так: ack -l --print0 --text from | xargs -0 -n 1 sed -i -e 's/from/to/g' - person Josh Strater; 31.05.2011
comment
Спасибо, исправил текст inline. - person Emil Sit; 31.05.2011
comment
Обратите внимание: не все команды grep, ack, perl, sed используют один и тот же вариант регулярного выражения. Поскольку Ack написан на perl, вы можете использовать одно и то же предложение from в обоих, если вы перенаправите ack в perl. - person Lloeki; 25.05.2012
comment
1-е решение по какой-то причине не работает в OS X ... кажется, что весь список имен файлов, возвращаемый grep, считается одним именем файла - person Petr Peller; 17.04.2016

Альтернативой sed является использование rpl (например, доступно на http://rpl.sourceforge.net/ или в вашем GNU / Дистрибутив Linux), например rpl --recursive --verbose --whole-words 'F' 'A' grades/

person Bernhard E. Reiter    schedule 17.09.2012
comment
Как бы вы использовали это в сценарии? В конце концов я остановился на: ag -l "$1" | xargs sed -i '' -e "s/$1/$2/g" но меня беспокоит расширение аргумента после удаления одинарных кавычек - person Connor; 22.10.2018

Типичная комбинация (find|grep|ack|ag|rg)-xargs-sed имеет несколько проблем:

  • Трудно запомнить и исправить. Например, если забыть параметр xargs -r, команда будет запущена, даже если файлы не найдены, что может вызвать проблемы.
  • Получение списка файлов и фактическая замена используют разные инструменты интерфейса командной строки и могут иметь другое поведение поиска.

Этих проблем было достаточно для такой агрессивной и опасной операции, как рекурсивный поиск и замена, чтобы начать разработку специального инструмента: мес.

Ранние тесты показывают, что его производительность находится между ag и rg и решает следующие проблемы, с которыми я сталкиваюсь с ними:

  • Один вызов может фильтровать по имени файла и содержимому. Следующая команда ищет слово ошибка во всех исходных файлах с указанием v1:

    mo -f 'src/.*v1.*' -p bug -w

  • После того, как результаты поиска будут удовлетворительными, можно добавить фактическую замену ошибки на исправление:

    mo -f 'src/.*v1.*' -p bug -w -r fix

person Geert Fannes    schedule 28.05.2021
comment
Думаю, было бы важно прямо упомянуть, что вы - главный автор продвигаемого вами инструмента. - person kelvin; 29.05.2021

comment() { 
}
doc() { 
}
function agr { 
doc 'usage: from=sth to=another agr [ag-args]'
comment -l --files-with-matches

ag -0 -l "$from" "${@}" | pre-files "$from" "$to"
}
pre-files() {
doc 'stdin should be null-separated list of files that need replacement; $1 the string to replace, $2 the replacement.'
comment '-i backs up original input files with the supplied extension (leave empty for no backup; needed for in-place replacement.)(do not put whitespace between -i and its arg.)'
comment '-r, --no-run-if-empty
              If  the  standard input does not contain any nonblanks,
              do not run the command.  Normally, the command  is  run
              once  even  if there is no input.  This option is a GNU
              extension.'

AGR_FROM="$1" AGR_TO="$2" xargs -r0 perl -pi.pbak -e 's/$ENV{AGR_FROM}/$ENV{AGR_TO}/g'
}

Вы можете использовать это так:

from=str1 to=sth agr path1 path2 ...

Не указывайте пути, чтобы использовать текущий каталог. Обратите внимание, что необходимо установить ag, xargs и perl в PATH.

person HappyFace    schedule 29.07.2019