在shell脚本中检索正则表达式后的单词

Ais*_*rni 12 regex shell

我正在尝试从具有元数据的文本文件中检索特定字段,如下所示:

project=XYZ; cell=ABC; strain=C3H; sex=F; age=PQR; treatment=None; id=MLN
Run Code Online (Sandbox Code Playgroud)

我有以下脚本来检索字段 'cell'

while read line
do
cell="$(echo $line | cut -d";" -f7 )"
echo  $cell
fi
done < files.txt
Run Code Online (Sandbox Code Playgroud)

但是下面的脚本检索整个字段cell=ABC,而我只想要'ABC'字段中的值,如何在同一行代码中检索正则表达式之后的值?

mkl*_*nt0 22

如果提取一个(或者,通常,通过独特捕获组捕获的值的非重复集)是足够的,你正在运行bash,ksh或者zsh,考虑使用正则表达式匹配操作,=~:[[ string =~ regex ]]:

向@AdrianFrühwirth提出要求kshzsh解决方案的要点.

示例输入字符串:

string='project=XYZ; cell=ABC; strain=C3H; sex=F; age=PQR; treatment=None; id=MLN'
Run Code Online (Sandbox Code Playgroud)

=~接下来讨论Shell特定的使用方法; =~最后可以找到通过shell函数实现的多shell实现.


庆典

特殊BASH_REMATCH数组变量接收匹配操作的结果:element 0包含整个匹配,element 1包含第一个捕获组(括号内的子表达式)匹配,依此类推.

bash 3.2+:

[[ $string =~ \ cell=([^;]+) ]] && cell=${BASH_REMATCH[1]} # -> $cell == 'ABC'
Run Code Online (Sandbox Code Playgroud)

bash 4.x:
虽然上面的特定命令有效,但在bash中使用正则表达式文字4.x是错误的,特别是在涉及字边界断言时\<\>Linux上; 例如,[[ a =~ \<a ]]莫名其妙地不匹配; 解决方法:使用中间变量(未引用!):re='\a'; [[ a =~ $re ]]工作(也在bash上3.2+).

bash 3.0 and 3.1- 或设置后shopt -s compat31:
引用正则表达式使其工作:

[[ $string =~ ' cell=([^;]+)' ]] && cell=${BASH_REMATCH[1]}  # -> $cell == 'ABC'
Run Code Online (Sandbox Code Playgroud)

KSH

ksh语法是一样的bash,除了:

  • 包含匹配字符串的特殊数组变量的名称是.sh.match({...}即使只隐式引用第一个元素,也必须包含该名称${.sh.match}):
[[ $string =~ \ cell=([^;]+) ]] && cell=${.sh.match[1]} # -> $cell == 'ABC'
Run Code Online (Sandbox Code Playgroud)

zsh的

zsh语法也类似于来砸,以下情况除外:

  • 必须引用正则表达式文字 - 为了简单起见,或者至少是一些 shell元字符,例如. ;
    • 您可以,但不必双重引用作为变量值提供的正则表达式.
    • 请注意这种引用行为与bash 3.2+的基本不同之处:zsh仅出于语法原因需要引用,并始终将结果字符串作为一个整体视为正则表达式,无论是否引用它或部分引用.
  • 2个变量包含匹配结果:
    • $MATCH包含整个匹配的字符串
    • 数组变量$match仅包含捕获组的匹配项(请注意,zsh数组以索引开头,1并且您不需要将变量名称包含在{...}引用数组元素中)
 [[ $string =~ ' cell=([^;]+)' ]] && cell=$match[1] # -> $cell == 'ABC'
Run Code Online (Sandbox Code Playgroud)

=~作为shell函数的运算符的多shell实现reMatch

以下shell功能抽象了之间的差异bash,ksh,zsh相对于所述=~操作员; 匹配在数组变量中返回${reMatches[@]}.

作为@AdrianFrühwirth笔记,编写可移植的(跨zsh,ksh,bash)使用此代码,您需要执行setopt KSH_ARRAYSzsh,以使其阵列开始指数0; 作为副作用,您还必须${...[]}在引用数组时使用语法,如kshbash).

应用于我们的示例,我们得到:

  # zsh: make arrays behave like in ksh/bash: start at *0*
[[ -n $ZSH_VERSION ]] && setopt KSH_ARRAYS

reMatch "$string" ' cell=([^;]+)' && cell=${reMatches[1]}
Run Code Online (Sandbox Code Playgroud)

壳功能:

# SYNOPSIS
#   reMatch string regex
# DESCRIPTION
#   Multi-shell implementation of the =~ regex-matching operator;
#   works in: bash, ksh, zsh
#
#   Matches STRING against REGEX and returns exit code 0 if they match.
#   Additionally, the matched string(s) is returned in array variable ${reMatch[@]},
#   which works the same as bash's ${BASH_REMATCH[@]} variable: the overall
#   match is stored in the 1st element of ${reMatch[@]}, with matches for
#   capture groups (parenthesized subexpressions), if any, stored in the remaining
#   array elements.
#   NOTE: zsh arrays by default start with index *1*.
# EXAMPLE:
#   reMatch 'This AND that.' '^(.+) AND (.+)\.' # -> ${reMatch[@]} == ('This AND that.', 'This', 'that')
function reMatch {
  typeset ec
  unset -v reMatch # initialize output variable
  [[ $1 =~ $2 ]] # perform the regex test
  ec=$? # save exit code
  if [[ $ec -eq 0 ]]; then # copy result to output variable
    [[ -n $BASH_VERSION ]] && reMatch=( "${BASH_REMATCH[@]}" )
    [[ -n $KSH_VERSION ]]  && reMatch=( "${.sh.match[@]}" )
    [[ -n $ZSH_VERSION ]]  && reMatch=( "$MATCH" "${match[@]}" )
  fi
  return $ec
}
Run Code Online (Sandbox Code Playgroud)

注意:

  • function reMatch(而不是reMatch())用于声明函数,这是ksh真正创建局部变量所必需的typeset.