Как мне найти и заменить каждое вхождение:
subdomainA.example.com
с
subdomainB.example.com
в каждом текстовом файле в дереве каталогов /home/www/
рекурсивно?
Как мне найти и заменить каждое вхождение:
subdomainA.example.com
с
subdomainB.example.com
в каждом текстовом файле в дереве каталогов /home/www/
рекурсивно?
find /home/www \( -type d -name .git -prune \) -o -type f -print0 | xargs -0 sed -i 's/subdomainA\.example\.com/subdomainB.example.com/g'
От man find
:
-print0 (только для GNU
find
) указываетfind
использовать нулевой символ (\0
) вместо пробела в качестве выходного разделителя между найденными путями. Это более безопасный вариант, если ваши файлы могут содержать пробелы или другие специальные символы. Рекомендуется использовать-print0
аргумент, чтобыfind
, если вы используете-exec <command>
илиxargs
(-0
аргумент необходим вxargs
.)
Примечание. Не запускайте эту команду в папке, содержащей git repo - изменения в .git могут повредить ваш индекс git.
find /home/www/ -type f -exec \
sed -i 's/subdomainA\.example\.com/subdomainB.example.com/g' {} +
По сравнению с другими ответами здесь это проще, чем у большинства, и использует sed вместо perl, что и требовался исходный вопрос.
Самый простой способ для меня -
grep -rl oldtext . | xargs sed -i 's/oldtext/newtext/g'
Все трюки почти одинаковы, но мне нравится этот:
find <mydir> -type f -exec sed -i 's/<string1>/<string2>/g' {} +
find <mydir>
: найдите в каталоге.
-type f
:
Файл имеет тип: обычный файл
-exec command {} +
:
Этот вариант действия -exec выполняет указанную команду в выбранных файлах, но командная строка создается путем добавления каждое имя выбранного файла в конце; общее количество вызовов команды будет намного меньше, чем количество согласованные файлы. Командная строка построена почти так же, как xargs создает свои командные строки. Только один экземпляр `{} 'разрешено внутри команды. Команда запускается в стартовом каталоге.
cd /home/www && find . -type f -print0 |
xargs -0 perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g'
Для меня самое легкое решение для запоминания - fooobar.com/questions/2977/..., то есть:
sed -i '' -e 's/subdomainA/subdomainB/g' $(find /home/www/ -type f)
ПРИМЕЧАНИЕ: -i ''
решает проблему OSX sed: 1: "...": invalid command code .
ПРИМЕЧАНИЕ. Если файлов для обработки слишком много, вы получите Argument list too long
. Обходной путь - используйте find -exec
или xargs
решение, описанное выше.
Для тех, кто использует серебряный искатель (ag
)
ag SearchString -l0 | xargs -0 sed -i 's/SearchString/Replacement/g'
Так как ag игнорирует файл git/hg/svn файл/папки по умолчанию, это безопасно запускать внутри репозитория.
Чтобы сократить рекурсивные файлы sed
через, вы могли бы grep
для вашего экземпляра строки:
grep -rl <oldstring> /path/to/folder | xargs sed -i s^<oldstring>^<newstring>^g
Если вы запустите man grep
, вы заметите, что вы также можете определить флаг --exlude-dir="*.git"
, если вы хотите опустить поиск по каталогам .git, избегая проблем с индексами git, как другие вежливо указали.
Приведем вас к:
grep -rl --exclude-dir="*.git" <oldstring> /path/to/folder | xargs sed -i s^<oldstring>^<newstring>^g
Один приятный oneliner как дополнительный. Использование git grep.
git grep -lz 'subdomainA.example.com' | xargs -0 perl -i'' -pE "s/subdomainA.example.com/subdomainB.example.com/g"
Этот совместим с репозиториями git и немного проще:
Linux:
git grep -l 'original_text' | xargs sed -i 's/original_text/new_text/g'
Mac:
git grep -l 'original_text' | xargs sed -i '' -e 's/original_text/new_text/g'
(Благодаря http://blog.jasonmeridth.com/posts/use-git-grep-to-replace-strings-in-files-in-your-git-repository/)
find /home/www/ -type f -exec perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g' {} +
find /home/www/ -type f
отобразит все файлы в/home/www/(и его подкаталоги).
Флаг "-exec" сообщает find для запуска следующей команды для каждого найденного файла.
perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g' {} +
- это запуск команды по файлам (по одному за раз). {}
заменяется именами файлов.
+
в конце команды сообщает find
создать одну команду для многих имен файлов.
На странице find
man:
"Командная строка построена так же, как и
xargs строит свои командные строки.
Таким образом, вы можете достичь своей цели (и обрабатывать имена файлов, содержащие пробелы), не используя xargs -0
или -print0
.
Я просто нуждался в этом и не был доволен скоростью доступных примеров. Поэтому я придумал свой собственный:
cd /var/www && ack-grep -l --print0 subdomainA.example.com | xargs -0 perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g'
Ack-grep очень эффективен при поиске соответствующих файлов. Эта команда заменила ~ 145 000 файлов ветром, в то время как другие заняли так много времени, что я не мог дождаться их завершения.
Прямой метод, если вам нужно исключить каталоги (--exclude-dir=.svn
), а также могут иметь имена файлов с пробелами (используя 0Byte с grep -Z
и xargs -0
grep -rlZ oldtext . --exclude-dir=.svn | xargs -0 sed -i 's/oldtext/newtext/g'
grep -lr 'subdomainA.example.com' | while read file; do sed -i "s/subdomainA.example.com/subdomainB.example.com/g" "$file"; done
Я думаю, что большинство людей не знают, что они могут что-то передать в файл "while read" и избегают этих неприятных аргументов -print0, в то время как сохраняются пробелы в именах файлов.
Дальнейшее добавление echo
до того, как sed позволит вам увидеть, какие файлы будут изменяться, прежде чем делать это.
Вы можете использовать awk для решения этой проблемы, как показано ниже,
for file in `find /home/www -type f`
do
awk '{gsub(/subdomainA.example.com/,"subdomainB.example.com"); print $0;}' $file > ./tempFile && mv ./tempFile $file;
done
надеюсь, что это поможет вам!
Попробуйте следующее:
sed -i 's/subdomainA/subdomainB/g' `grep -ril 'subdomainA' *`
#!/usr/local/bin/bash -x
find * /home/www -type f | while read files
do
sedtest=$(sed -n '/^/,/$/p' "${files}" | sed -n '/subdomainA/p')
if [ "${sedtest}" ]
then
sed s'/subdomainA/subdomainB/'g "${files}" > "${files}".tmp
mv "${files}".tmp "${files}"
fi
done
Если вы не против использования vim
вместе с инструментами grep
или find
, вы можете выполнить ответ, указанный пользователем Gert в этой ссылке → How выполнить замену текста в иерархии больших папок?.
Здесь сделка:
рекурсивно grep для строки, которую вы хотите заменить в определенном пути, и взять только полный путь к соответствующему файлу. (это будет $(grep 'string' 'pathname' -Rl)
.
(необязательно), если вы хотите сделать предварительную резервную копию этих файлов в централизованном каталоге, возможно, вы также можете использовать это: cp -iv $(grep 'string' 'pathname' -Rl) 'centralized-directory-pathname'
после этого вы можете редактировать/заменять по желанию в vim
по схеме, аналогичной той, которая указана в приведенной ссылке:
:bufdo %s#string#replacement#gc | update
Немного старой школы, но это работало на OS X.
Есть несколько обманов:
• Будет редактировать файлы с расширением .sls
только в текущем каталоге
• .
должен быть экранирован, чтобы гарантировать, что sed
не оценивает их как "любой символ"
• ,
используется как разделитель sed
вместо обычного /
Также обратите внимание, что это редактирование шаблона Jinja для передачи variable
в пути import
(но это не в тему).
Сначала убедитесь, что ваша команда sed делает то, что вы хотите (это приведет только к печати изменений в stdout, это не изменит файлы):
for file in $(find . -name *.sls -type f); do echo -e "\n$file: "; sed 's,foo\.bar,foo/bar/\"+baz+\"/,g' $file; done
Отредактируйте команду sed по мере необходимости, как только вы готовы внести изменения:
for file in $(find . -name *.sls -type f); do echo -e "\n$file: "; sed -i '' 's,foo\.bar,foo/bar/\"+baz+\"/,g' $file; done
Обратите внимание на -i ''
в команде sed, я не хотел создавать резервную копию исходных файлов (как описано в Редактирование на месте с sed на OS X или в комментарии Роберта Луджо на этой странице).
Счастливые люди седанов!
чтобы избежать изменения.
но все же
(может быть, не очень хорошо в идее, лежащей в основе корня домена)
find /home/www/ -type f -exec sed -i 's/\bsubdomainA\.example\.com\b/\1subdomainB.example.com\2/g' {} \;
Согласно этому сообщению в блоге:
find . -type f | xargs perl -pi -e 's/oldtext/newtext/g;'
Я просто использую топы:
find . -name '*.[c|cc|cp|cpp|m|mm|h]' -print0 | xargs -0 tops -verbose replace "verify_noerr(<b args>)" with "__Verify_noErr(<args>)" \
replace "check(<b args>)" with "__Check(<args>)"
Здесь версия, которая должна быть более общей, чем большинство; например, он не требует find
(с использованием du
). Для этого нужны xargs
, которые есть только в некоторых версиях Plan 9 (например, 9front).
du -a | awk -F' ' '{ print $2 }' | xargs sed -i -e 's/subdomainA\.example\.com/subdomainB.example.com/g'
Если вы хотите добавить фильтры, такие как расширения файлов, используйте grep
:
du -a | grep "\.scala$" | awk -F' ' '{ print $2 }' | xargs sed -i -e 's/subdomainA\.example\.com/subdomainB.example.com/g'
чтобы изменить несколько файлов (и сохранить резервную копию как *.bak
):
perl -p -i -e "s/\|/x/g" *
возьмет все файлы в каталоге и заменит |
с х называется "Perl pie" (просто как пирог)
Для Qshell (qsh) для IBMi, а не bash как помечено OP.
Ограничения команд qsh:
Таким образом, решение в qsh:
PATH='your/path/here'
SEARCH=\'subdomainA.example.com\'
REPLACE=\'subdomainB.example.com\'
for file in $( find ${PATH} -P -type f ); do
TEMP_FILE=${file}.${RANDOM}.temp_file
if [ ! -e ${TEMP_FILE} ]; then
touch -C 819 ${TEMP_FILE}
sed -e 's/'$SEARCH'/'$REPLACE'/g' \
< ${file} > ${TEMP_FILE}
mv ${TEMP_FILE} ${file}
fi
done
Предостережения:
Если вы хотите использовать это без полного уничтожения своего репозитория SVN, вы можете сказать "найти", чтобы игнорировать все скрытые файлы, выполнив:
find . \( ! -regex '.*/\..*' \) -type f -print0 | xargs -0 sed -i 's/subdomainA.example.com/subdomainB.example.com/g'
Используя комбинацию grep
и sed
for pp in $(grep -Rl looking_for_string)
do
sed -i 's/looking_for_string/something_other/g' "${pp}"
done
Для замены всех вхождений в репозитории git вы можете использовать:
git ls-files -z | xargs -0 sed -i 's/subdomainA\.example\.com/subdomainB.example.com/g'
Смотрите Список файлов в локальном git repo? для других опций, чтобы перечислить все файлы в репозитории. Опция -z
сообщает git отделить имена файлов с нулевым байтом, что гарантирует, что xargs
(с опцией -0
) может разделять имена файлов, даже если они содержат пробелы или что-то еще.
perl -p -i -e 's/oldthing/new_thingy/g' `grep -ril oldthing *`
Проще всего использовать нижеследующее в командной строке
find /home/www/ -type f|xargs perl -pi -e 's/subdomainA\.example\.com/subdomainB.example.com/g'