单个变量的多个替换

时间:2014-09-18 13:05:05

标签: macos bash

对于以下变量:

var="/path/to/my/document-001_extra.txt"

我只需要/ [斜杠]和_ [下划线]之间的部分。 此外,还需要删除- [破折号]。

换句话说:document 001

这是我到目前为止所做的:

var="${var##*/}"

var="${var%_*}"

var="${var/-/ }"

工作正常,但我正在寻找一种更紧凑的替代模式,这将使我失去三重var=...

使用sed,awk,cut等可能对此更有意义,但我正在寻找纯粹的bash解决方案。

需要在GNU bash下运行,版本3.2.51(1)-release

2 个答案:

答案 0 :(得分:1)

在编辑问题后谈论模式而不是正则表达式时,我现在将向您展示如何实际bash中使用正则表达式:)

[[ $var =~ ^.*/(.*)-(.*)_ ]] && var="${BASH_REMATCH[@]:1:2}"

以前遗憾地使用的参数扩展不能嵌套在bash中(除非您使用了不明智的eval黑客,即使这样,它也不会比上面的行清楚。)

=~运算符在左侧的字符串和右侧的正则表达式之间执行匹配。正则表达式中的括号定义匹配组。如果匹配成功,则[[ ... ]]的退出状态为零,因此执行&&之后的代码。 (提醒:不要将流程退出状态的“0 =成功,非零=失败”约定与常见的布尔约定“0 = false,1 = true”混淆。)

BASH_REMATCH是一个数组参数,bash在成功的正则表达式匹配后设置。数组的第一个元素包含正则表达式匹配的全文;以下每个元素都包含相应捕获组的内容。

${foo[@]:x:y}参数扩展会生成数组的y个元素,从索引x开始。在这种情况下,它只是写${BASH_REMATCH[1]} ${BASH_REMATCH[2]}的简短方法。 (另外,虽然var=${BASH_REMATCH[*]:1:2}也会有效,但我倾向于使用@来强调你几乎总是想在其他地方使用@代替*这一事实上下文。)

答案 1 :(得分:0)

以下两种方法都可以正常工作。虽然第二个对错位字符很敏感(如果在最后一个/之后有-_,它将会失败。

var=$(IFS=_ read s _ <<<"$var"; IFS=-; echo ${s##*/})

var=$(IFS=/-_; a=($var); echo "${a[@]:${#a[@]} - 3:2}")