-1

我有这个脚本的问题。该脚本应该遍历所有文件以及所有子目录和子文件(递归)。如果文件以扩展名 .txt 结尾,我需要用新的字符/单词替换文本中的字符/单词,然后将其复制到现有目录中。第一个参数是我需要开始搜索的目录,第二个是旧的 char/word,第三个是新的 char/word,第四个是要将文件复制到的目录。该脚本遍历文件,但仅进行替换并从原始目录复制文件。这是脚本

#!/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
4

2 回答 2

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 "$@"

相同的功能 funk 使用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 "$@"

cp我使用

  • 开关:没有破坏,-n以免覆盖现有文件。如果您的版本mv支持它,请使用它,除非您真的想覆盖文件。
  • -v开关:详细,将向您显示移动的文件(可选)。
  • -tswitch:后面跟-t一个目录告诉复制到这个目录。使用cp这种方式是一件非常好的事情:想象你提供一个现有文件而不是提供一个现有目录:如果没有这个功能,这个文件将被覆盖多次(好吧,如果你省略该选项,就会出现这种情况)!使用此功能,现有文件将保持安全。-n

还要注意--. 如果您的cpsed支持它(GNUsed和就是这种情况cp),请始终使用它!这意味着现在选项结束。如果您不使用它并且文件名以连字符开头,则会混淆试图解释选项的命令。有了这个--,我们可以安全地放置一个可能以连字符开头的文件名。

请注意,在搜索替换模式中,我用/转义形式替换了所有斜杠,\/以免在sed斜杠碰巧出现在searchreplace时与分隔符冲突。

享受!

于 2013-06-30T14:44:22.097 回答
-2

正如所指出的,循环查找输出不是一个好主意。它也不支持搜索和替换中的斜线。

检查gniourf_gniourf 的答案


使用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 "$@"

尽管子目录中可能有同名的文件,但这些文件将被覆盖。这对你来说是个问题吗?

于 2013-06-30T14:25:33.553 回答