首页 > 解决方案 > 组合多个参数扩展的正确语法是什么?

问题描述

我当前的代码:

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

标签: bashshellvariablesrefactoringsimplify

解决方案


您不能组合多个参数扩展,但是...


...您可以简化此代码!

最大的收获是使用已经可用的工具。

  1. 而不是循环,让我们使用grep. 它应该在发生 RegEx 模式时做一些事情,所以:
grep -E "$rbv_reg" "$1" # -E is for extended RegEx
  1. 我猜你的模式不区分大小写,所以让我们用-i标志禁用它。
  2. 匹配后循环中断,所以让我们-m 1在第一次匹配后停止处理文件。
  3. 您想将大写转换为小写,所以让我们通过管道传递tr
grep -m 1 -E -i "$rbv_reg" "$1" | tr '[:upper:]' '[:lower:]'
  1. 然后,您将一些字符替换为//[^0-9a-z\.\-]/,将其管道化即可sed
grep -m 1 -E -i "$rbv_reg" "$1" | tr '[:upper:]' '[:lower:]' | sed 's/[^0-9a-z\.\-]//g'
  1. 最后,让我们将输出抓取到变量:
ruby_version="$( grep -m 1 -E -i '$rbv_reg' '$1' | tr '[:upper:]' '[:lower:]' | sed 's/[^0-9a-z\.\-]//g' )"
  1. 由于您无论如何都在打印新行,所以让我们使用简单echo而不是printf
  2. 剩下的就是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 中工作。


推荐阅读