2013-06-30 66 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。 –