Shell通用等效的Bash Substring替换$ {foo / a / b}

时间:2016-02-11 14:34:12

标签: bash shell find sh

是否存在与shell无关的等效Bash子串替换:

foo=Hello
echo ${foo/o/a} # will output "Hella"

大多数情况下,我可以使用bash,因此这不是问题,但是当与find -exec结合使用时,它不起作用。例如,要将所有.cpp个文件重命名为.c,我想使用:

# does not work
find . -name '*.cpp' -exec mv {} {/.cpp$/.c}

目前,我正在使用:

# does work, but longer
while read file; do 
    mv "$file" "${file/.cpp$/.c}"; 
done <<< $(find . -name '*.cpp') 

理想情况下,可以在脚本中使用的解决方案更好!

2 个答案:

答案 0 :(得分:4)

使用find-exec可以执行此操作:

find . -name '*.cpp' -exec bash -c 'f="$1"; mv "$f" "${f/.cpp/.c}"' - '{}' \;

但是,这会为每个文件名分叉bash -c,因此使用xargsfor这样的循环更好,因为性能原因:

while IFS= read -d '' -r file; do 
    mv "$file" "${file/.cpp/.c}" 
done < <(find . -name '*.cpp' -print0) 

答案 1 :(得分:1)

顺便说一下,使用bash的替代方法是使用rename。如果您拥有rename命令的 cool 版本,该命令随perl一起提供,您可以执行以下操作:

find -name '*.cpp' -exec rename 's/\.cpp$/.c/' {} +

上面的示例假设您拥有GNU findutils,因此您不需要传递当前目录,因为它是默认值。如果您没有GNU findutils,则需要明确传递它:

find . -name '*.cpp' -exec rename 's/\.cpp$/.c/' {} +