bash - 组合多个参数扩展的正确语法是什么?
问题描述
我当前的代码:
while read -r rbv_line || [[ -n "$rbv_line" ]]; do
if [[ "${rbv_line}" =~ ${rbv_reg} ]]; then
rbv_downcase="${BASH_REMATCH[0],,}" &&
ruby_version="${rbv_downcase//[^0-9a-z\.\-]/}" &&
((reg_matches="${reg_matches}"+1))
printf "\n"
printf "Setting Ruby version: %s\n" "${ruby_version}"
break
fi
done < "${1}"
它做我想要的。但是我很想知道是否可以进一步简化此代码,希望有人可以帮助我理解语法。
如果你看到这两行:
rbv_downcase="${BASH_REMATCH[0],,}" &&
ruby_version="${rbv_downcase//[^0-9a-z\.\-]/}" &&
最初,我尝试使用以下方法将它们组合成一个:
ruby_version="${BASH_REMATCH[0],,//[^0-9a-z\.\-]/}"
那是行不通的。
有没有办法将这两个参数扩展(,,
和//[^0-9a-z\.\-]/
)结合起来,或者通过中间变量传递它是正确的方法?
你可以在这里查看最新版本的代码: https ://github.com/octopusnz/scripts
解决方案
您不能组合多个参数扩展,但是...
...您可以简化此代码!
最大的收获是使用已经可用的工具。
- 而不是循环,让我们使用
grep
. 它应该在发生 RegEx 模式时做一些事情,所以:
grep -E "$rbv_reg" "$1" # -E is for extended RegEx
- 我猜你的模式不区分大小写,所以让我们用
-i
标志禁用它。 - 匹配后循环中断,所以让我们
-m 1
在第一次匹配后停止处理文件。 - 您想将大写转换为小写,所以让我们通过管道传递
tr
:
grep -m 1 -E -i "$rbv_reg" "$1" | tr '[:upper:]' '[:lower:]'
- 然后,您将一些字符替换为
//[^0-9a-z\.\-]/
,将其管道化即可sed
:
grep -m 1 -E -i "$rbv_reg" "$1" | tr '[:upper:]' '[:lower:]' | sed 's/[^0-9a-z\.\-]//g'
- 最后,让我们将输出抓取到变量:
ruby_version="$( grep -m 1 -E -i '$rbv_reg' '$1' | tr '[:upper:]' '[:lower:]' | sed 's/[^0-9a-z\.\-]//g' )"
- 由于您无论如何都在打印新行,所以让我们使用简单
echo
而不是printf
- 剩下的就是
if [ -n "$ruby_version" ]
增加reg_matches
最后,我们得到:
ruby_version="$(
grep -m 1 -E -i '$rbv_reg' '$1' |
tr '[:upper:]' '[:lower:]' |
sed 's/[^0-9a-z\.\-]//g'
)"
if [ -n "$ruby_version" ]; then
reg_matches="$((reg_matches+1))"
echo
echo "Setting Ruby version: $ruby_version"
fi
上述代码的优点是它并不真正依赖于 Bash,并且应该在任何 POSIX Bourne 兼容的 shell 中工作。