【问题标题】:Shell generic equivalent of Bash Substring replacement ${foo/a/b}Shell 通用等效的 Bash 子字符串替换 ${foo/a/b}
【发布时间】:2023-04-09 04:02:01
【问题描述】:

是否存在独立于 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') 

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

【问题讨论】:

    标签: bash shell find sh


    【解决方案1】:

    使用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) 
    

    【讨论】:

    • 确认它在 MacOSX 版本 3.2.57(1) 上也不能正常工作。
    • @anubhava 我的错,我错过了- '{}' 部分。你有任何关于它的作用的文件吗?
    • Here is a working demo of above find command 顺便说一句,我也有GNU bash, version 4.3.33(1),它在那里也工作得很好。
    【解决方案2】:

    顺便说一句,使用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/' {} +
    

    【讨论】:

    • 你测试了吗? .cpp$ 似乎对我不起作用。
    • 不是真的,因为缺少测试文件。让我准备一个小测试。
    • 单引号和双引号也要切换。
    • 感谢rename 提示替代品与find。但是您缺少应用查找命令的文件夹:find . 而不是 find?
    • @gniourf_gniourf 好的,保留。
    猜你喜欢
    • 2023-03-04
    • 2021-08-19
    • 1970-01-01
    • 2016-05-31
    • 1970-01-01
    • 2012-08-09
    • 2011-06-21
    • 1970-01-01
    • 2017-01-13
    相关资源
    最近更新 更多