BASH表达式在一次操作中替换字符串的开头和结尾?

时间:2010-04-23 03:15:34

标签: bash

这是一个困扰我一段时间的简单问题。我经常发现我在某个目录中有许多输入文件,我想通过替换开始和结束部分来构造输出文件名。例如,鉴于此:

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

当然,上述方法无效。有谁知道会有什么意义吗?我只是想在这里保存一些打字。

4 个答案:

答案 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