我的脚本有问题。该脚本应该通过所有文件和所有子目录和子文件(递归)。如果文件以扩展名.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
答案 0 :(得分:6)
你在这里使用了很多不好的做法:缺少报价,你正在解析ls
的输出......只要文件名包含其他有趣符号的空格,这一切就会中断。
如果您使用bash的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 "$@"
使用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
开关:没有clobber,以便不覆盖现有文件。如果您的mv
版本支持它,请使用它,除非您确实要覆盖文件。-v
开关:详细,将显示已移动的文件(可选)。-t
开关:-t
后跟一个目录告诉复制到此目录。以这种方式使用cp
是一件非常好的事情:想象而不是给出现有的目录,你给出一个现有的文件:没有这个功能,这个文件将会被多次覆盖(好吧,如果省略-n
选项就会出现这种情况)!使用此功能,现有文件将保持安全。另请注意--
的使用。如果您的cp
和sed
支持它(GNU sed
和cp
就属于这种情况),请始终使用它!它意味着现在选项的结束。如果您不使用它,并且文件名以连字符开头,则会混淆尝试解释选项的命令。使用此--
,我们可以放置一个可能以连字符开头的文件名。
请注意,在搜索和替换模式中,我将所有斜杠/
替换为其转义格式\/
,以免与其冲突如果斜线恰好出现在搜索或替换中,则sed
中的分隔符。
享受!
答案 1 :(得分:-2)
正如所指出的,循环查找输出不是一个好主意。它也不支持搜索和替换中的斜杠。
如何使用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 "$@"
虽然您可能在子目录中具有相同名称的文件,但这些文件将被覆盖。这是你的问题吗?