Изменение нескольких файлов
следующая команда правильно изменяет содержимое 2 файлов.
sed -i 's/abc/xyz/g' xaa1 xab1
но то, что мне нужно сделать, это изменить несколько таких файлов динамически, и я не знаю имена файлов. Я хочу написать команду, которая будет читать все файлы из текущего каталога, начиная с xa* и sed следует изменить содержимое файла.
9 ответов:
еще лучше:
for i in xa*; do sed -i 's/asd/dfg/g' $i doneпотому что никто не знает, сколько файлов есть, и это легко нарушить ограничения командной строки.
вот что происходит, когда слишком много файлов:
# grep -c aaa * -bash: /bin/grep: Argument list too long # for i in *; do grep -c aaa $i; done 0 ... (output skipped) #
Я удивлен, что никто не упомянул аргумент-exec для поиска, который предназначен для этого типа прецедента, хотя он запустит процесс для каждого соответствующего имени файла:
find . -type f -name 'xa*' -exec sed -i 's/asd/dsg/g' {} \;в качестве альтернативы можно использовать xargs, который вызовет меньше процессов:
find . -type f -name 'xa*' | xargs sed -i 's/asd/dsg/g'
вы можете использовать grep и sed вместе. Это позволяет рекурсивно искать подкаталоги.
Linux: grep -r -l <old> * | xargs sed -i 's/<old>/<new>/g' OS X: grep -r -l <old> * | xargs sed -i '' 's/<old>/<new>/g' For grep: -r recursively searches subdirectories -l prints file names that contain matches For sed: -i extension (Note: An argument needs to be provided on OS X)
эти команды не будут работать по умолчанию
sedэто поставляется с Mac OS X.С
man 1 sed:-i extension Edit files in-place, saving backups with the specified extension. If a zero-length extension is given, no backup will be saved. It is not recommended to give a zero-length extension when in-place editing files, as you risk corruption or partial content in situations where disk space is exhausted, etc.пробовал
sed -i '.bak' 's/old/new/g' logfile*и
for i in logfile*; do sed -i '.bak' 's/old/new/g' $i; doneоба работают нормально.
@PaulR разместил это как комментарий, но люди должны рассматривать его как ответ (и этот ответ лучше всего подходит для моих нужд):
sed -i 's/abc/xyz/g' xa*Это будет работать для умеренного количества файлов, вероятно, порядка десятков, но наверное, не на порядок миллионы.
еще один более универсальный способ-использовать
find:sed -i 's/asd/dsg/g' $(find . -type f -name 'xa*')
я использую
findдля подобных задач. Это довольно просто: вы должны передать его в качестве аргумента дляsedтакой:
sed -i 's/EXPRESSION/REPLACEMENT/g' `find -name "FILE.REGEX"`таким образом, вам не нужно писать сложные циклы, и это просто увидеть, какие файлы вы собираетесь изменить, просто запустите
findперед запускомsed.
можно сделать
' xxxx 'текст u поиск и заменит его на'гггг'
grep -Rn '**xxxx**' /path | awk -F: '{print }' | xargs sed -i 's/**xxxx**/**yyyy**/'
если вы можете запустить скрипт, вот что я сделал для подобной ситуации:
используя словарь / hashMap (ассоциативный массив) и переменные для
sedкоманда, мы можем перебрать массив, чтобы заменить несколько строк. В том числе подстановочный знак вname_patternпозволит заменить в файлах с рисунком (это может быть что-то вродеname_pattern='File*.txt') в определенном каталоге (source_dir). Все изменения записываются вlogfileвdestin_dir#!/bin/bash source_dir=source_path destin_dir=destin_path logfile='sedOutput.txt' name_pattern='File.txt' echo "--Begin $(date)--" | tee -a $destin_dir/$logfile echo "Source_DIR=$source_dir destin_DIR=$destin_dir " declare -A pairs=( ['WHAT1']='FOR1' ['OTHER_string_to replace']='string replaced' ) for i in "${!pairs[@]}"; do j=${pairs[$i]} echo "[$i]=$j" replace_what=$i replace_for=$j echo " " echo "Replace: $replace_what for: $replace_for" find $source_dir -name $name_pattern | xargs sed -i "s/$replace_what/$replace_for/g" find $source_dir -name $name_pattern | xargs -I{} grep -n "$replace_for" {} /dev/null | tee -a $destin_dir/$logfile done echo " " echo "----End $(date)---" | tee -a $destin_dir/$logfileсначала объявляется массив пар, каждая пара является заменяющей строкой, затем
WHAT1будет заменен наFOR1иOTHER_string_to replaceбудет заменен наstring replacedв файлеFile.txt. В цикле массив считывается, первый член пары извлекается какreplace_what=$i, а второйreplace_for=$j. Элементfindкоманда ищет в каталоге имя файла (которое может содержать подстановочный знак) иsed -iкоманда заменяет в том же файле(ах), что было предварительно определено. Наконец, я добавилgrepперенаправлено в файл журнала для регистрации изменений, внесенных в файл (ы).это сработало для меня в
GNU Bash 4.3sed 4.2.2и основываясь на ответе Васяновикова за петля над кортежами в bash.
Comments