Изменение нескольких файлов



следующая команда правильно изменяет содержимое 2 файлов.



sed -i 's/abc/xyz/g' xaa1 xab1 


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

451   9  
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

    Ничего не найдено.