2013-06-30 3 views
-1

У меня проблема с этим скриптом. Сценарий должен проходить через все файлы и все подкаталоги и подфайлы (рекурсивно). Если файл заканчивается расширением .txt, мне нужно заменить символ/слово в тексте новым символом/словом, а затем скопировать его в существующий каталог. Первый аргумент - это каталог, в котором мне нужно запустить поиск, второй - старый символ/слово, третий - новый символ/слово и четвертый каталог для копирования файлов. Скрипт проходит через файлы, но только заменяет и копирует файлы из исходного каталога. Вот сценарийПроблема с рекурсивной оболочкой и расширения файлов

#!/bin/bash 

funk(){ 
    for file in `ls $1` 
    do 
    if [ -f $file ] 
    then 
     ext=${file##*.} 
     if [ "$ext" = "txt" ] 
     then 
     sed -i "s/$2/$3/g" $file 
     cp $file $4 
     fi 
    elif [ -d $file ] 
    then 
     funk $file $2 $3 $4 
    fi 
    done 
} 

if [ $# -lt 4 ] 
then 
    echo "Need more arg" 
    exit 2; 
fi 

cw=$1 
a=$2 
b=$3 
od=$4 
funk $cw $a $b $od 
+3

Ваш код сломается, как только появится имя файла/каталога, содержащее пробелы. См. [Здесь] (http://mywiki.wooledge.org/ParsingLs) для более подробного объяснения, почему вы никогда не должны использовать 'ls', как вы это делаете в своем коде. –

+0

В вашем вопросе не уточняется, что не работает. Может быть, это мои глаза, но ваши требования и ваше описание того, что делает сценарий, кажутся одинаковыми. – innaM

ответ

-2

Как указывалось, петля над выводом вывода не является хорошей идеей. Он также не поддерживает косые черты в поиске & заменить.

Проверить gniourf_gniourf's answer.


Как насчет использования find для этого?

#!/bin/bash 

funk() { 
    local dir=$1; shift 
    local search=$1; shift 
    local replace=$1; shift 
    local dest=$1; shift 

    mkdir -p "$dest" 
    for file in `find $dir -name *.txt`; do 
     sed -i "s/$search/$replace/g" "$file" 
     cp "$file" "$dest" 
    done 
} 

if [[ $# -lt 4 ]] ; then 
    echo "Need 4 arguments" 
    exit 2; 
fi 

funk "[email protected]" 

Хотя у вас могут быть файлы с одинаковыми именами в подкаталогах, они будут перезаписаны. Это проблема в вашем случае?

+6

'find' не следует использовать таким образом. Используйте '-exec' вместо цикла' for', который будет прерываться всякий раз, когда имя файла содержит пробелы: 'mkdir -p" $ 4 "; find "$ 1" -name "* .txt" -exec sed -i "s/$ 2/$ 3/g {} \; -exec cp {}" $ 4 "/ \;' –

+0

Это также сломается, если 'search' или символ 'replace' - это косая черта. –

+1

И зачем так часто создавать каталог назначения? – innaM

6

Здесь вы используете множество плохих практик: отсутствие цитат, вы разбираете вывод ls ... все это сломается, как только имя файла содержит пробел другого смешного символа.

Вам не нужна рекурсия, если вы используете globstar по желанию, или find.

Вот возможность с бывшим, что мы надеемся показать вам лучшие практики:

#!/bin/bash 

shopt -s globstar 
shopt -s nullglob 

funk() { 
    local search=${2//\//\\/} 
    local replace=${3//\//\\/} 

    for f in "$1"/**.txt; do 
     sed -i "s/$search/$replace/g" -- "$f" 
     cp -nvt "$4" -- "$f" 
    done 
} 

if (($#!=4)); then 
    echo >&2 "Need 4 arguments" 
    exit 1 
fi 

funk "[email protected]" 

Та же функция фанк с помощью find:

#!/bin/bash 

funk() { 
    local search=${2//\//\\/} 
    local replace=${3//\//\\/} 

    find "$1" -name '*.txt' -type f -exec sed -i "s/$search/$replace/g" -- {} \; -exec cp -nvt "$4" -- {} \; 
} 

if (($#!=4)); then 
    echo >&2 "Need 4 arguments" 
    exit 1 
fi 

funk "[email protected]" 

В cp я использую

  • -n переключатель: нет clobber, чтобы не перезаписывать существующий файл. Используйте его, если ваша версия mv поддерживает его, если вы на самом деле не хотите перезаписывать файлы.
  • -v switch: verbose, покажет вам перемещенные файлы (необязательно).
  • -t переключатель: -t, за которым следует каталог, сообщает, что копировать в этот каталог. Очень полезно использовать cp следующим образом: представьте, вместо того, чтобы предоставить существующий каталог , вы даете существующий файл : без этой функции этот файл будет перезаписан несколько раз (ну, это будет так, если вы опустите опцию -n)! с этой функцией существующий файл останется в безопасности.

Также обратите внимание на использование --. Если ваши cp и sed поддерживают его (в случае с GNU sed и cp), используйте его всегда!это означает конец опций теперь. Если вы не используете его, и если имя файла начинается с дефиса, это смущает команду, пытающуюся интерпретировать опцию. С помощью этого -- мы можем указать имя файла, которое может начинаться с дефиса.

Обратите внимание, что в поиске и заменить шаблонов Я заменил все слэшами / их сбежавшей формой \/, чтобы не конфликтовать с разделителем в sed если слэш происходит появляться в поиске или заменить ,

Наслаждайтесь!

+0

+1 для два решения как «globstar» - только bash 4. –

Смежные вопросы