Ответы:
cd /path/to/your/folder
sed -i 's/foo/bar/g' *
Появления «foo» будут заменены на «bar».
В системах BSD, таких как macOS, вам необходимо предоставить расширение для резервной копии, например -i '.bak'
или «риск повреждения или частичное содержимое» для man-страницы.
cd /path/to/your/folder
sed -i '.bak' 's/foo/bar/g' *
sed
, -i
требуется строка после нее, которая добавляется к старым именам файлов. Поэтому sed -i .bak 's/foo/bar/g' *.xx
перемещает все .xx
файлы к эквивалентному .xx.bak
имени и затем генерирует .xx
файлы с подстановкой foo → bar.
sed -i 's/foo\ with\ spaces/bar/g' *
. Я полагаю, вы узнали об этом так долго ... но так остаётся другим, которые находят ту же проблему.
sed -i -e 's/foo/bar/g' $(find /home/user/base/dir)
Аналогично ответу Каспара, но с флагом g, чтобы заменить все вхождения в строке.
find ./ -type f -exec sed -i 's/string1/string2/g' {} \;
Для глобального нечувствительного к регистру:
find ./ -type f -exec sed -i 's/string1/string2/gI' {} \;
LC_ALL=C find ./ -type f -exec sed -i '' -e 's/proc.priv/priv/g' {} \;
(см. Этот пост и этот )
--include=*.whatever
с -r
.git/
. Обязательно cd
опускайтесь на более низкий уровень.
git status
возвращается: error: bad index file sha1 signature.... fatal: index file corrupt
. Что дает?
Ответ @ kev хорош, но влияет только на файлы в ближайшем каталоге. В приведенном ниже примере используется grep для рекурсивного поиска файлов. Это работает для меня каждый раз.
grep -rli 'old-word' * | xargs -i@ sed -i 's/old-word/new-word/g' @
Распределение команд
Grep -r : --recursive , рекурсивно прочитать все файлы в каждом каталоге.
grep -l : --print-with-match , печатает имя каждого файла, у которого есть совпадение, вместо печати совпадающих строк.
grep -i : --ignore-case .
xargs : преобразовать STDIN в аргументы, следуйте этому ответу .
Команда xargs -i @ ~ содержит @ ~ : заполнитель для аргумента, который будет использоваться в определенной позиции в ~ команде ~ , знак @ - это заполнитель, который может быть заменен любой строкой.
sed -i : редактировать файлы на месте, без резервных копий.
СЭД с / регулярное выражение / замена / : заменой строки сопоставления регулярное выражение с заменой .
sed s / regexp / replace / g : global , делать замену для каждого совпадения вместо только первого совпадения.
grep --include={*.php,*.html,*.js} -rnl './' -e "old-word" | xargs -i@ sed -i 's/old-word/new-word/g' @
|
, также, почему -i
в команде xargs? Я прочитал в руководстве это устарело и должен использовать -I
вместо этого. И @
используется как разделитель для начала и конца для шаблона?
grep -rli 'old-word' * | xargs -I@ sed -i '' 's/2.0.0/latest/g' @
rli
) и @
знака, например
Это сработало для меня:
find ./ -type f -exec sed -i 's/string1/string2/' {} \;
Но это не так sed -i 's/string1/string2/g' *
. Может быть, «foo» не был строкой1, а «bar» - не строкой2.
find ./ -type f -exec sed -i '' -e 's/string1/string2/' {} \;
Есть несколько стандартных ответов на этот вопрос. Как правило, вы можете использовать find для рекурсивного вывода списка файлов, а затем выполнять операции с помощью sed или perl .
Для наиболее быстрого использования команда rpl гораздо проще запомнить. Вот замена (foo -> bar), рекурсивно для всех файлов:
rpl -R foo bar .
Вам, вероятно, понадобится установить его ( apt-get install rpl
или аналогичный).
Однако для более сложных заданий, которые включают регулярные выражения и обратную подстановку или переименование файлов, а также поиск и замену, наиболее общий и мощный инструмент, о котором я знаю, это repren , небольшой скрипт на Python, который я написал некоторое время назад для некоторых более сложные задачи переименования и рефакторинга. Причины, по которым вы можете предпочесть это:
Чтобы использовать это pip install repren
. Проверьте README для примеров.
Чтобы заменить строку в нескольких файлах, вы можете использовать:
grep -rl string1 somedir/ | xargs sed -i 's/string1/string2/g'
Например
grep -rl 'windows' ./ | xargs sed -i 's/windows/linux/g'
Чтобы заменить путь в файлах (избегая escape-символов), вы можете использовать следующую команду:
sed -i 's@old_path@new_path@g'
Знак @ означает, что все специальные символы должны игнорироваться в следующей строке.
Если в вашей строке есть косая черта (/), вы можете изменить разделитель на «+».
find . -type f -exec sed -i 's+http://example.com+https://example.com+g' {} +
Эта команда будет выполняться рекурсивно в текущем каталоге.
../domain.com
наdomain.com
Первая строка вхождения «foo» будет заменена на «bar». И вы можете использовать вторую строку для проверки.
grep -rl 'foo' . | xargs sed -i 's/foo/bar/g'
grep 'foo' -r * | awk -F: {'print $1'} | sort -n | uniq -c
grep -rl 'foo' . | xargs sed -i 's/foo/bar/g'
Если у вас есть список файлов, которые вы можете использовать
replace "old_string" "new_string" -- file_name1 file_name2 file_name3
Если у вас есть все файлы, которые вы можете использовать
replace "old_string" "new_string" -- *
Если у вас есть список файлов с расширением, вы можете использовать
replace "old_string" "new_string" -- *.extension
replace "old_string" "new_string" -- *.txt
replace
утилиту. Без этой информации этот ответ неполон.
«Вы также можете использовать find и sed, но я обнаружил, что эта маленькая строчка perl прекрасно работает.
perl -pi -w -e 's/search/replace/g;' *.php
"(Извлечено из 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' )
Если вы хотите найти строку search
и заменить ее replace
в нескольких файлах, это моя проверенная в бою формула в одну строку :
grep -RiIl 'search' | xargs sed -i 's/search/replace/g'
Быстрое объяснение grep:
-R
- рекурсивный поиск-i
- без учета регистра-I
пропустить двоичные файлы (вы хотите текст, верно?)-l
- распечатать простой список в качестве вывода. Необходим для других командЗатем вывод grep передается в sed (через xargs), который фактически используется для замены текста. -i
Флаг будет изменять файл напрямую. Снимите его для своего рода «пробного запуска».
Я придумал собственное решение, прежде чем нашел этот вопрос (и ответы). Я искал различные комбинации «заменить», «несколько» и «xml», потому что это было мое приложение, но не нашел именно этого.
Моя проблема: у меня были весенние xml-файлы с данными для тестовых случаев, содержащие сложные объекты. Рефакторинг исходного кода java изменил много классов и не применим к файлам данных xml. Чтобы сохранить данные тестовых случаев, мне нужно было изменить все имена классов во всех XML-файлах, распределенных по нескольким каталогам. Все это при сохранении резервных копий оригинальных XML-файлов (хотя это не было обязательным, так как контроль версий спас бы меня здесь).
Я искал некоторую комбинацию find
+ sed
, потому что она работала для меня в других ситуациях, но не с несколькими заменами одновременно.
Затем я нашел ответ на запрос ubuntu, и он помог мне построить мою командную строку:
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' {} \;
findstr /spin /c:"quéquieresbuscar" *.xml
это будет удобно.
Действительно хромая, но я не мог заставить любую из команд sed работать правильно на OSX, поэтому вместо этого я сделал эту глупую вещь:
:%s/foo/bar/g
:wn
^ - скопируйте эти три строки в мой буфер обмена (да, включите завершающий перевод строки), затем:
VI *
и удерживайте нажатой команду -v, пока не появится сообщение, что файлов больше не осталось.
Тупой ... Hacky ... эффективный ...
На MacBook Pro я использовал следующее (вдохновлено https://stackoverflow.com/a/19457213/6169225 ):
sed -i '' -e 's/<STR_TO_REPLACE>/<REPLACEMENT_STR>/g' *
-i ''
убедитесь, что вы не делаете никаких резервных копий.
-e
для современного регулярного выражения.
-e
просто говорит sed, что следующий токен - это команда. Для расширенных регулярных выражений используйте -E
вместо этого.
Редактор потока изменяет несколько файлов «на месте» при вызове с -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 *
работает.
скрипт для мультиредактной команды
multiedit [-n PATTERN] OLDSTRING NEWSTRING
Из ответа Каспара я сделал скрипт bash, чтобы принимать аргументы командной строки и, необязательно, ограничивать имена файлов, соответствующие шаблону. Сохраните в вашем $ PATH и сделайте исполняемый файл, затем просто используйте команду выше.
Вот сценарий:
#!/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
Если файл содержит обратную косую черту (обычно пути), вы можете попробовать что-то вроде этого:
sed -i -- 's,<path1>,<path2>,g' *
например:
sed -i -- 's,/foo/bar,/new/foo/bar,g' *.sh (in all shell scripts available)
Чтобы сохранить свой личный английский узел, я написал служебный скрипт, который помогает рекурсивно заменить несколько пар старой / новой строки для всех файлов в каталоге.
Несколько пар старой / новой строки управляются в хэш-карте.
Dir может быть установлен через командную строку или переменную окружения, карта жестко запрограммирована в скрипте, но вы можете изменить код для загрузки из файла, если это необходимо.
Требуется 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 -i@ sed -i "s/$key/${itemMap[$key]}/g" @
done
echo -e "\nDone."
exit
Использование команды ack будет намного быстрее:
ack '25 Essex' -l | xargs sed -i 's/The\ fox \jump/abc 321/g'
Также, если у вас есть пробел в результатах поиска. Вы должны избежать этого.
Я привожу пример для исправления распространенной ошибки 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' .
Я только что проверил первый скрипт, и второй тоже должен работать. Будьте осторожны с escape-символами, я думаю, что в большинстве случаев проще использовать greptile. Конечно, вы можете делать много интересных вещей с помощью sed, и для этого предпочтительнее освоить его с помощью xargs.
Я нашел это из другого поста (не помню, какой именно), и хотя он не самый элегантный, он прост и, как начинающий пользователь 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
Существует более простой способ с использованием простого файла сценария:
# 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
Не беспокойтесь о количестве строк замены, которые вы добавляете, они не будут действовать, если старая строка не найдена.
.gitlab-ci.yml
или a travis.yml
). Каждый поворот, заключающийся в написании сценария для его последующего выполнения, является анти-паттерном, поскольку вам нужно будет создать сценарий для создания сценария (а я в большинстве случаев
$ replace "From" "To" - `find / path / to / folder -type f`
(replace - утилита замены строк MySQL Database System)