这是一个困扰我一段时间的简单问题。我经常发现我在某个目录中有许多输入文件,我想通过替换开始和结束部分来构造输出文件名。例如,鉴于此:
source/foo.c
source/bar.c
source/foo_bar.c
我经常写这样的BASH表达式:
for f in source/*.c; do
a="obj/${f##*/}"
b="${a%.*}.obj"
process "$f" "$b"
done
生成命令
process "source/foo.c" "obj/foo.obj"
process "source/bar.c "obj/bar.obj"
process "source/foo_bar.c "obj/foo_bar.obj"
以上的作品,但它比我喜欢的语言更多,我宁愿避免临时变量。理想情况下会有一些命令可以一次性替换字符串的开头和结尾,这样我就可以编写类似的内容:
for f in source/*.c; do process "$f" "obj/${f##*/%.*}.obj"; done
当然,上述方法无效。有谁知道会有什么意义吗?我只是想在这里保存一些打字。
答案 0 :(得分:3)
这不是世界上最漂亮的东西,但您可以使用正则表达式对要挑选的内容进行分组,然后参考BASH_REMATCH
数组:
if [[ $f =~ ^source/(.*).c$ ]] ; then f="obj/${BASH_REMATCH[1]}.o"; fi
答案 1 :(得分:1)
您不必担心您的代码是否“更啰嗦”。事实上,有点冗长是没有害处的,考虑一下它会改进你(或其他人)对脚本的理解程度。此外,为了提高性能,使用bash的内部字符串操作比调用外部命令要快得多。最后,每次使用它都不会重新输入命令吗?那么为什么担心这些命令已经出现在你的脚本中呢?
答案 2 :(得分:0)
不直接在bash中。你当然可以使用sed:
b="$(sed 's|^source/(.*).c$|obj/$1.obj|' <<< "$f")"
答案 3 :(得分:0)
为什么不简单地使用cd删除“source /”部分?
这样我们可以避免临时变量a和b:
for f in $(cd source; printf "%s\n" *.c); do
echo process "source/${f}" "obj/${f%.*}.obj"
done