Как заменить строку в нескольких файлах в командной строке linux

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

Ответ 1

cd /path/to/your/folder
sed -i 's/foo/bar/g' *

Возникновение "foo" будет заменено на "bar".

Ответ 2

Подобно Kaspar, но с флагом g, чтобы заменить все вхождения в строке.

find ./ -type f -exec sed -i 's/string1/string2/g' {} \;

Для глобального нечувствительного к регистру:

find ./ -type f -exec sed -i 's/string1/string2/gI' {} \;

Ответ 3

@kev ответ хорош, но влияет только на файлы в непосредственной директории. В приведенном ниже примере используется grep для рекурсивного поиска файлов. Он работает для меня каждый раз.

grep -rli 'old-word' * | xargs [email protected] sed -i 's/old-word/new-word/g' @

Ответ 4

Это сработало для меня:

find ./ -type f -exec sed -i 's/string1/string2/' {} \;

Howerver, этого не произошло: sed -i 's/string1/string2/g' *. Возможно, "foo" не предназначался для string1 и "bar" not string2.

Ответ 5

Есть несколько стандартных ответов на это уже перечисленные. Как правило, вы можете использовать find, чтобы рекурсивно перечислить файлы, а затем выполните операции с sed или perl.

Для наиболее быстрого использования вы можете найти команду rpl гораздо легче запомнить. Вот замена (foo → bar), рекурсивно на все файлы:

rpl -R foo bar .

Вам, вероятно, потребуется установить его (apt-get install rpl или аналогичный).

Однако для более сложных заданий, которые включают регулярные выражения и обратную подстановку, или переименования файлов, а также поиск и замену, самым общим и мощным инструментом, о котором я знаю, является repren, небольшой Python script Я написал некоторое время назад для некоторых более сложных задач переименования и рефакторинга. Причины, по которым вы, возможно, предпочтете это:

  • Поддержка переименования файлов, а также поиск и замена содержимого файла.
  • Перед выполнением поиска и замены ознакомьтесь с изменениями.
  • Поддерживать регулярные выражения с обратной подстановкой, целыми словами, нечувствительностью к регистру и сохранением регистров (замените foo → bar, Foo → Bar, FOO → BAR).
  • Работает с несколькими заменами, в том числе свопами (foo → bar и bar → foo) или наборами неповторимых замен (foo → bar, f → x).

Чтобы использовать его, pip install repren. Проверьте пример README.

Ответ 6

Чтобы заменить строку в нескольких файлах, вы можете использовать:

grep -rl string1 somedir/ | xargs sed -i 's/string1/string2/g'

Например

grep -rl 'windows' ./ | xargs sed -i 's/windows/linux/g'

Исходный блог

Ответ 7

Чтобы заменить путь в файлах (избегая escape-символов), вы можете использовать следующую команду:

sed -i '[email protected][email protected][email protected]'

Знак @означает, что все специальные символы следует игнорировать в следующей строке.

Ответ 8

Если в вашей строке есть косая черта (/), вы можете изменить разделитель на "+".

find . -type f -exec sed -i 's+http://example.com+https://example.com+g' {} +

Эта команда будет выполняться рекурсивно в текущем каталоге.

Ответ 9

Первая строка вхождения "foo" будет заменена на "bar". И вы можете использовать вторую строку для проверки.

grep -rl 'foo' . | xargs sed -i 's/foo/bar/g'
grep 'foo' -r * | awk -F: {'print $1'} | sort -n | uniq -c

Ответ 10

Если у вас есть список файлов, которые вы можете использовать

replace "old_string" "new_string" -- file_name1 file_name2 file_name3

Если у вас есть все файлы, которые вы можете использовать

replace "old_string" "new_string" -- *

Если у вас есть список файлов с расширением, вы можете использовать

replace "old_string" "new_string" -- *.extension

Ответ 11

"Вы также можете использовать find и sed, но я обнаружил, что эта маленькая строчка perl прекрасно работает.

perl -pi -w -e 's/search/replace/g;' *.php
  • -e означает выполнить следующую строку кода.
  • -i означает редактировать в -p кружевном
  • -w написать предупреждение
  • -p loop

"(Извлечено из http://www.liamdelahunty.com/tips/linux_search_and_replace_multiple_files.php)

Мои лучшие результаты получены от использования perl и grep (чтобы убедиться, что файл имеет выражение поиска)

perl -pi -w -e 's/search/replace/g;' $( grep -rl 'search' )

Ответ 12

Я придумал свое решение, прежде чем нашел этот вопрос (и ответы). Я искал разные комбинации "replace" "несколько" и "xml", потому что это было мое приложение, но не нашло его.

Моя проблема: у меня были spring xml файлы с данными для тестовых примеров, содержащие сложные объекты. Рефакторинг в исходном коде java изменил много классов и не применился к файлам данных xml. Чтобы сохранить данные тестовых случаев, мне нужно было изменить все имена классов во всех xml файлах, распределенных по нескольким каталогам. Все при сохранении резервных копий исходных xml файлов (хотя это не было обязательным, так как контроль версий меня спасет здесь).

Я искал некоторую комбинацию find + sed, потому что он работал у меня в других ситуациях, но не с несколькими заменами сразу.

Затем я нашел запрос ubuntu response, и это помогло мне создать мою командную строку:

find -name "*.xml" -exec sed -s --in-place=.bak -e 's/firstWord/newFirstWord/g;s/secondWord/newSecondWord/g;s/thirdWord/newThirdWord/g' {} \;

И это сработало отлично (ну, у моего дела было шесть разных замен). Обратите внимание, что он будет касаться всех *.xml файлов в текущем каталоге. Из-за этого, и если вы подотчетны системе управления версиями, вы можете сначала фильтровать и переходить только к sed тем, у кого есть нужные строки; как:

find -name "*.xml" -exec grep -e "firstWord" -e "secondWord" -e "thirdWord" {} \; -exec sed -s --in-place=.bak -e 's/firstWord/newFirstWord/g;s/secondWord/newSecondWord/g;s/thirdWord/newThirdWord/g' {} \;

Ответ 13

grep --include={*.php,*.html} -rnl './' -e "old" | xargs [email protected] sed -i 's/old/new/g' @

Ответ 14

На MacBook Pro я использовал следующее (вдохновлено fooobar.com/questions/33995/...):

sed -i '' -e 's/<STR_TO_REPLACE>/<REPLACEMENT_STR>/g' *

-i '' гарантирует, что вы не делаете никаких резервных копий.

-e для современного регулярного выражения.

Ответ 15

Редактор потока модифицирует несколько файлов "inplace" при вызове с помощью переключателя -i, который берет файл резервной копии, заканчивающийся как аргумент. Так

sed -i.bak 's/foo/bar/g' *

заменяет foo на bar во всех файлах в этой папке, но не входит в подпапки. Однако это приведет к созданию нового файла .bak для каждого файла в вашем каталоге. Чтобы сделать это рекурсивно для всех файлов в этом каталоге и во всех его подкаталогах, вам понадобится помощник, например find, для перемещения по дереву каталогов.

find ./ -print0 | xargs -0 sed -i.bak 's/foo/bar/g' *

find позволяет вам дополнительно ограничивать, какие файлы изменять, указав при необходимости дополнительные аргументы, например find ./ -name '*.php' -or -name '*.html' -print0.


Примечание: GNU sed не требует окончания файла, также будет работать sed -i 's/foo/bar/g' *; FreeBSD sed требует расширения, но позволяет пространство между ними, поэтому sed -i .bak s/foo/bar/g * работает.

Ответ 16

script для команды multiedit

multiedit [-n PATTERN] OLDSTRING NEWSTRING

Из ответа Kaspar я сделал bash script, чтобы принять аргументы командной строки и, возможно, ограничить имена файлов, соответствующие шаблону. Сохраните в своей $PATH и создайте исполняемый файл, а затем просто используйте команду выше.

Здесь script:

#!/bin/bash
_help="\n
Replace OLDSTRING with NEWSTRING recursively starting from current directory\n
multiedit [-n PATTERN] OLDSTRING NEWSTRING\n

[-n PATTERN] option limits to filenames matching PATTERN\n
Note: backslash escape special characters\n
Note: enclose STRINGS with spaces in double quotes\n
Example to limit the edit to python files:\n
multiedit -n \*.py \"OLD STRING\" NEWSTRING\n"

# ensure correct number of arguments, otherwise display help...
if [ $# -lt 2 ] || [ $# -gt 4 ]; then echo -e $_help ; exit ; fi
if [ $1 == "-n" ]; then  # if -n option is given:
        # replace OLDSTRING with NEWSTRING recursively in files matching PATTERN
        find ./ -type f -name "$2" -exec sed -i "s/$3/$4/g" {} \;
else
        # replace OLDSTRING with NEWSTRING recursively in all files
        find ./ -type f -exec sed -i "s/$1/$2/" {} \;
fi

Ответ 17

Действительно хромой, но я не мог заставить любую команду sed работать прямо на OSX, поэтому вместо этого я сделал эту тупую вещь:

:%s/foo/bar/g
:wn

^ - скопируйте эти три строки в мой буфер обмена (да, включите окончание новой строки), затем:

vi *

и удерживайте команду-v, пока не сообщите, что файлов не осталось.

Тупой... Hacky... эффективный...

Ответ 18

Если файл содержит обратные косые черты (обычно пути), вы можете попробовать что-то вроде этого:

sed -i -- 's,<path1>,<path2>,g' *

Пример:

sed -i -- 's,/foo/bar,/new/foo/bar,g' *.sh (in all shell scripts available)

Ответ 19

Чтобы сохранить личный английский node, я написал утилиту script, которая поможет заменить несколько папок старой/новой строки, для всех файлов в каталоге рекурсивно.

Несколько паре старой/новой строки управляются в хэш-карте.

Диск может быть установлен с помощью командной строки или переменной окружения, карта жестко закодирована в script, но вы можете изменить код для загрузки из файла, если это необходимо.

Требуется bash 4.2, из-за некоторой новой функции.

en_standardize.sh:

#! /bin/bash
# (need bash 4.2+,)
# 
# Standardize phonetic symbol of English.
# 
# format:
#   en_standardize.sh [<dir>]
# 
# params:
# * dir
#   target dir, optional,
#   if not specified then use environment variable "$node_dir_en",
#   if both not provided, then will not execute,
# * 
# 

paramCount=$#

# figure target dir,
if [ $paramCount -ge 1 ]; then # dir specified
    echo -e "dir specified (in command):\n\t$1\n"
    targetDir=$1
elif [[ -v node_dir_en ]]; then # environable set,
    echo -e "dir specified (in environment vairable):\n\t$node_dir_en\n"
    targetDir=$node_dir_en
else # environable not set,
    echo "dir not specified, won't execute"
    exit
fi

# check whether dir exists,
if [ -d $targetDir ]; then
    cd $targetDir
else
    echo -e "invalid dir location:\n\t$targetDir\n"
    exit
fi

# initial map,
declare -A itemMap
itemMap=( ["ɪ"]="i" ["ː"]=":" ["ɜ"]="ə" ["ɒ"]="ɔ" ["ʊ"]="u" ["ɛ"]="e")

# print item maps,
echo 'maps:'
for key in "${!itemMap[@]}"; do
    echo -e "\t$key\t->\t${itemMap[$key]}"
done
echo -e '\n'

# do replace,
for key in "${!itemMap[@]}"; do
    grep -rli "$key" * | xargs [email protected] sed -i "s/$key/${itemMap[$key]}/g" @
done

echo -e "\nDone."
exit

Ответ 20

Использование команды ack будет намного быстрее:

ack '25 Essex' -l | xargs sed -i 's/The\ fox \jump/abc 321/g'

Также, если у вас есть пробел в результатах поиска. Вы должны избежать этого.

Ответ 21

Если вы хотите найти строку search и заменить ее на replace в нескольких файлах, это моя проверенная в бою формула в одну строку:

grep -RiIl 'search' | xargs sed -i 's/search/replace/g'

Быстрое объяснение grep:

  • -R - рекурсивный поиск
  • -i - без учета регистра
  • -I - пропустить двоичные файлы (вам нужен текст, верно?)
  • -l - распечатывать простой список как вывод. Необходим для других команд

Затем вывод grep передается в sed (через xargs), который фактически используется для замены текста. Флаг -i изменит файл напрямую. Снимите его для своего рода "пробного запуска".

Ответ 22

Команда ниже может быть использована для поиска файлов и замены файлов:

find . | xargs grep 'search string' | sed 's/search string/new string/g'

Например

find . | xargs grep abc | sed 's/abc/xyz/g'

Ответ 23

Я приводил пример для исправления общей ошибки shebang в источниках python.

Вы можете попробовать подход grep/sed. Вот один из них, который работает с GNU sed и не разбивает репозиторий git:

$ grep -rli --exclude '*.git*' '#!/usr/bin/python' . | xargs -I {} \
gsed -i '' -e 's/#!\/usr\/bin\/python/#!\/usr\/bin\/env python/' {}

Или вы можете использовать greptile:)

$ greptile -x .py -l -i -g '#!/usr/bin/env python' -r '#!/usr/bin/python' .

Я только что проверил первый script, а второй должен работать. Будьте осторожны с escape-символами, я думаю, что в большинстве случаев лучше использовать greptile. Конечно, вы можете делать много интересного с sed, и для этого может быть предпочтительнее использовать его с помощью xargs.

Ответ 24

Я нашел это из другого сообщения (не могу вспомнить, какой), и хотя он не самый элегантный, он прост и как новичок, пользователь Linux не дал мне никаких проблем.

for i in *old_str* ; do mv -v "$i" "${i/\old_str/new_str}" ; done

Если у вас есть пробелы или другие специальные символы, используйте \

for i in *old_str\ * ; do mv -v "$i" "${i/\old_str\ /new_str}" ; done

для строк в подкаталогах используйте **

for i in *\*old_str\ * ; do mv -v "$i" "${i/\old_str\ /new_str}" ; done

Ответ 25

Существует более простой способ использования простого файла сценария:

   # sudo chmod +x /bin/replace_string_files_present_dir

откройте файл в gedit или редакторе по вашему выбору, я использую gedit здесь.

   # sudo gedit /bin/replace_string_files_present_dir

Затем в редакторе вставьте следующее в файл

   #!/bin/bash
   replace "oldstring" "newstring" -- *
   replace "oldstring1" "newstring2" -- *
   #add as many lines of replace as there are your strings to be replaced for 
   #example here i have two sets of strings to replace which are oldstring and 
   #oldstring1 so I use two replace lines.

Сохраните файл, закройте gedit, затем выйдите из терминала или просто закройте его, а затем запустите, чтобы иметь возможность загрузить новый скрипт, который вы добавили.

Перейдите в каталог, где у вас есть несколько файлов, которые вы хотите редактировать. Затем запустите:

  #replace_string_files_present_dir

Нажмите клавишу ввода, и это автоматически заменит oldstring и oldstring1 во всех файлах, которые их содержат, на правильные newstring и newstring1 соответственно.

Он пропустит все каталоги и файлы, которые не содержат старых строк.

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

#replace_string_files_present_dir

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

replace "oldstring" "newstring" -- *

в конце файла /bin/replace_string_files_present_dir.

Чтобы добавить новую строку замены, просто откройте созданный нами скрипт, набрав в терминале следующее:

sudo gedit /bin/replace_string_files_present_dir

Не беспокойтесь о количестве строк замены, которые вы добавляете, они не будут иметь эффекта, если oldstring не найдена.

Ответ 26

$replace "From" "To" - `find/path/to/folder -type f`

(replace - утилита замены строк базы данных MySQL)