Shell Bash 子字符串替换 ${foo/a/b} 的通用等价物

Shell generic equivalent of Bash Substring replacement ${foo/a/b}

是否有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') 

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

使用 find-exec 你可以这样做:

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

然而,这将为每个文件名创建 bash -c,因此出于性能原因,使用 xargs 或这样的 for 循环更好:

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

顺便说一句,使用 bash 的替代方法是使用 rename。如果你有 cool 版本的 rename 命令,它与 perl 一起提供,你可以这样做:

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

上面的例子假设你有 GNU findutils,有了这个你不需要传递当前目录,因为它是默认的。如果你没有GNUfindutils,你需要显式传递:

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