我正在尝试从具有元数据的文本文件中检索特定字段,如下所示:
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提出要求ksh
和zsh
解决方案的要点.
示例输入字符串:
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
语法是一样的bash
,除了:
.sh.match
({...}
即使只隐式引用第一个元素,也必须包含该名称${.sh.match}
):[[ $string =~ \ cell=([^;]+) ]] && cell=${.sh.match[1]} # -> $cell == 'ABC'
Run Code Online (Sandbox Code Playgroud)
该zsh
语法也类似于来砸,以下情况除外:
;
zsh
仅出于语法原因需要引用,并始终将结果字符串作为一个整体视为正则表达式,无论是否引用它或部分引用.$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_ARRAYS
的zsh
,以使其阵列开始指数0
; 作为副作用,您还必须${...[]}
在引用数组时使用语法,如ksh
和bash
).
应用于我们的示例,我们得到:
# 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
.