2013-06-30 63 views
-1

我遇到了這個腳本的問題。該腳本應該通過所有文件和所有子目錄和子文件(遞歸)。如果文件以擴展名.txt結尾,我需要用新的字符/單詞替換文本中的字符/單詞,然後將其複製到現有目錄中。第一個參數是我需要開始搜索的目錄,第二個參數是舊的char/word,第三個是新的char/word,第四個是將文件複製到的目錄。該腳本通過文件,但只做替換,並從原始目錄複製文件。這是腳本遞歸Shell腳本和文件擴展名問題

#!/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」;找到「$ 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我使用

  • the -n切換:無clobber,以免覆蓋現有文件。如果您的版本mv支持它,請使用它,除非您確實要覆蓋文件。
  • -v切換:詳細,將顯示您移動的文件(可選)。
  • -t切換:-t後跟一個目錄告訴複製到這個目錄。以這種方式使用cp是一件非常好的事情:想象一下,如果不是給出現有的目錄,而是給現有的文件:沒有此功能,該文件將被覆蓋多次(當然,如果您省略-n選項)!使用此功能,現有文件將保持安全。

另請注意使用--。如果您的cpsed支持它(這是GNU sedcp的情況),請始終使用它!這意味着選項現在結束。如果你不使用它,並且如果文件名以連字符開頭,它會混淆嘗試解釋選項的命令。有了這個--,我們可以放置一個可能以連字符開頭的文件名。

注意的是,在搜索更換模式我更換了所有他們逃脫形式\/斜線/從而不與分離器交鋒中sed如果斜線恰好出現在搜索更換

享受!

+0

+1 「globstar」這兩個解決方案僅僅是bash 4。 –