Использование a
вместо w
должно позволить вам обновить файл вместо создания нового / перезаписать все в существующем файле.
См. этот ответ для разница в режимах.
cd /path/to/your/folder
sed -i 's/foo/bar/g' *
Возникновение «foo» будет заменено на «bar».
«Вы также можете использовать 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' )
Команда «Ниже» может использоваться для первого поиска файлов и замены файлов
find. | строка поиска xargs grep | sed 's / search string / new string / g'
, например find. | xargs grep abc | sed 's / abc / xyz / g'
Редактор потока модифицирует несколько файлов «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 *
работает.
$ заменить «От» «Кому» - `find / path / to / folder -type f`
(заменить - утилиту замены строк базы данных MySQL)
для команды multiedit
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
Я придумал свое решение, прежде чем нашел этот вопрос (и ответы). Я искал разные комбинации «replace» «несколько» и «xml», потому что это было мое приложение, но не нашло его.
Моя проблема: у меня были весенние xml-файлы с данными для тестирования случаев, содержащих сложные объекты. Рефакторинг в исходном коде java изменил много классов и не применился к файлам данных xml. Чтобы сохранить данные тестовых случаев, мне нужно было изменить все имена классов во всех xml-файлах, распределенных по нескольким каталогам. Все, сохраняя резервные копии исходных xml-файлов (хотя это не было обязательным, так как управление версией меня спасло здесь).
Я искал некоторую комбинацию find
+ sed
, потому что он работал для меня в других ситуациях, но не с несколькими заменами сразу.
Затем я нашел ask 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' {} \;
findstr /spin /c:"quéquieresbuscar" *.xml
Это будет удобно.
– manuelvigarcia
8 June 2016 в 11:07
grep --include={*.php,*.html} -rnl './' -e "old" | xargs -i@ sed -i 's/old/new/g' @
Есть несколько стандартных ответов на это уже перечисленные. Как правило, вы можете использовать find для рекурсивного перечня файлов, а затем выполнять операции с sed или perl.
Для наиболее быстрого использования вы можете найти команду rpl намного легче запомнить. Вот замена (foo -> bar), рекурсивно на все файлы:
rpl -R foo bar .
Вам, вероятно, потребуется установить его (apt-get install rpl
или подобное).
Однако для более сложных заданий, которые включают регулярные выражения и обратную подстановку, или переименование файлов, а также поиск и замену, самым общим и мощным инструментом, о котором я знаю, является repren , небольшой скрипт Python, который я написал некоторое время назад для некоторых более сложных задач переименования и рефакторинга. Причины, по которым вы, возможно, предпочтете это:
Чтобы использовать его, pip install repren
. Проверьте примеры README .
Чтобы сохранить мой личный английский узел, я написал скрипт утилиты, который помогает заменить несколько папок старой / новой строки для всех файлов в каталоге рекурсивно.
Несколько паре старой / новой строки управляются в хэш-карте.
Директору можно установить через командную строку или переменную окружения, карта жестко закодирована в скрипте, но вы можете изменить код для загрузки из файла, если это необходимо.
Это требует 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
Я приводил пример для исправления общей ошибки shebang в источниках python.
Вы можете попробовать подход grep / sed. Вот один из них, который работает с GNU sed и не будет разрушать git repo:
$ 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.
Это сработало для меня:
find ./ -type f -exec sed -i 's/string1/string2/' {} \;
Однако этого не произошло: sed -i 's/string1/string2/g' *
. Возможно, «foo» не предназначался для string1 и «bar» not string2.
find ./ -type f -exec sed -i '' -e 's/string1/string2/' {} \;
– Shaheen Ghiassy
16 April 2018 в 11:03
Если ваша строка имеет косую черту (/), вы можете изменить разделитель на «+».
find . -type f -exec sed -i 's+http://example.com+https://example.com+g' {} +
Эта команда будет работать рекурсивно в текущем каталоге.
../domain.com
на domain.com
– Jack Rogers
8 March 2018 в 18:29
Чтобы заменить путь в файлах (избегая escape-символов), вы можете использовать следующую команду:
sed -i 's@old_path@new_path@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
– tsveti_iko
6 April 2016 в 12:56
Действительно хромой, но я не мог заставить любую команду sed работать прямо на OSX, поэтому я сделал эту тупую вещь:
:%s/foo/bar/g
:wn
^ - скопируйте эти три строки в свой буфер обмена (да, включите окончание новой строки), затем:
vi *
и удерживайте команду-v, пока не сообщите, что файлов нет.
Dumb. ..hacky ... эффективный ...
Как и ответ Каспара, но с флагом 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' {} \;
(см. этот пост и этот [ )
– Sheljohn
13 August 2015 в 15:01
--include=*.whatever
с -r
– PJ Brunet
23 February 2017 в 19:41
.git/
. Убедитесь, что cd
до нижнего уровня.
– erikprice
7 March 2017 в 21:27
{}
или вы получите сообщение об ошибке.
– FearlessFuture
18 July 2017 в 20:25
Я нашел это из другого сообщения (не помню, какой), и хотя он не самый элегантный, он прост и, как новичок, пользователь 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
Ответ на kev хороший, но влияет только на файлы в непосредственной директории. В приведенном ниже примере используется grep для рекурсивного поиска файлов. Он работает для меня каждый раз.
grep -rli 'old-word' * | xargs -i@ sed -i 's/old-word/new-word/g' @
grep --include={*.php,*.html,*.js} -rnl './' -e "old-word" | xargs -i@ sed -i 's/old-word/new-word/g' @
– Dennis
6 March 2014 в 00:20
|
, также, почему -i
в команде xargs? Я прочитал в руководстве, это устарело, и вместо этого следует использовать -I
. И @
используется как разделитель для начала и конца шаблона?
– Edson Horacio Junior
9 November 2015 в 15:57
Чтобы заменить строку в нескольких файлах, вы можете использовать:
grep -rl matchstring somedir/ | xargs sed -i 's/string1/string2/g'
Например:
grep -rl 'windows' ./ | xargs sed -i 's/windows/linux/g'
Если файл содержит обратную косую черту (обычно пути), вы можете попробовать что-то вроде этого:
sed -i -- 's,<path1>,<path2>,g' *
ex:
sed -i -- 's,/foo/bar,/new/foo/bar,g' *.sh (in all shell scripts available)
Первая строка вхождения «foo» будет заменена на «bar». И вы можете использовать вторую строку для проверки.
grep -rl 'foo' . | xargs sed -i 's/foo/bar/g'
grep 'foo' -r * | awk -F: {'print $1'} | sort -n | uniq -c
sed
,-i
требуется строка после нее, которая добавляется к старым именам файлов. Таким образом,sed -i .bak 's/foo/bar/g' *.xx
перемещает все.xx
файлы в эквивалентное имя.xx.bak
, а затем генерирует файлы.xx
с заменой foo → bar. – Anaphory 4 October 2014 в 23:35sed -i 's/foo\ with\ spaces/bar/g' *
. Полагаю, вы так долго узнали ... но таким образом он остается для других, обнаруживающих ту же проблему. – manuelvigarcia 21 December 2016 в 09:44