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

标签 regex shell

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

project=XYZ; cell=ABC; strain=C3H; sex=F; age=PQR; treatment=None; id=MLN

我有以下脚本来检索字段 'cell'
while read line
do
cell="$(echo $line | cut -d";" -f7 )"
echo  $cell
fi
done < files.txt

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

最佳答案

提取一个值 (或者,通常,由不同捕获组捕获的一组非重复值)就足够了,您正在运行 bash , ksh , 或 zsh ,考虑使用 正则表达式匹配运算符,=~ :[[ string =~ regex ]] :

向@Adrian Frühwirth 致敬,了解 ksh 的要点和 zsh解决方案。

示例输入字符串:

string='project=XYZ; cell=ABC; strain=C3H; sex=F; age=PQR; treatment=None; id=MLN'

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

bash

特价BASH_REMATCH数组变量接收匹配操作的结果:元素0包含整个匹配项,元素 1第一个捕获组的(带括号的子表达式)匹配,依此类推。
bash 3.2+ :
[[ $string =~ \ cell=([^;]+) ]] && cell=${BASH_REMATCH[1]} # -> $cell == 'ABC'
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'

克什
ksh语法与 bash 中的相同, 除了:
  • 包含匹配字符串的特殊数组变量的名称是 .sh.match (您必须将名称括在 {...} 中,即使只是用 ${.sh.match} 隐式引用第一个元素):
  • [[ $string =~ \ cell=([^;]+) ]] && cell=${.sh.match[1]} # -> $cell == 'ABC'
    

    zsh
    zsh语法也类似于 bash,除了:
  • 正则表达式文字必须被引用 - 为了简单起见,或者至少是一些 shell 元字符,例如 ; .
  • 你可以,但不需要双引号作为变量值提供的正则表达式。
  • 请注意此引用行为与 bash 3.2+ 的引用行为有何根本不同:zsh仅出于语法原因需要引用,并且始终将结果字符串作为一个整体视为正则表达式,无论它或其中的一部分是否被引用。
  • 有 2 个变量包含匹配结果:
  • $MATCH包含整个匹配的字符串
  • 数组变量 $match仅包含捕获组的匹配项(注意 zsh 数组以索引 1 开头,并且您不需要将变量名括在 {...} 中以引用数组元素)
  •  [[ $string =~ ' cell=([^;]+)' ]] && cell=$match[1] # -> $cell == 'ABC'
    
    =~的多shell实现运算符作为 shell 函数 reMatch
    以下shell函数抽象了bash之间的差异, ksh , zsh关于 =~运算符(operator);匹配在数组变量 ${reMatches[@]} 中返回.

    正如@Adrian Frühwirth 指出的那样,要使用此编写可移植(跨 zshkshbash )代码,您需要执行 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]}
    

    shell 函数:

    # 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
    }
    

    笔记:
  • function reMatch (与 reMatch() 相反)用于声明函数,这是 ksh 所必需的使用 typeset 真正创建局部变量.
  • 关于regex - 在 shell 脚本中检索正则表达式后的单词,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22537804/

    相关文章:

    javascript正则表达式多模式搜索

    JavaScript 正则表达式从查询中删除变量

    java - 正则表达式匹配变量声明

    bash - psql : warning: extra command-line argument "from" ignored

    javascript - 用于匹配 CSV 字段值内的引号的正则表达式

    python - 使用正则表达式匹配字符串(特定字符串组合除外)

    linux - Sed 在位置前插入符号

    arrays - 如何在 bash 中逐行将命令输出转换为数组?

    linux - 有没有办法通过 shell 脚本上的 SFTP 下载与模式匹配的文件?

    bash - 简单地将命令的输出 fork 并重定向到/dev/null