awk在regexp

时间:2018-10-29 23:48:21

标签: regex linux bash variables awk

我想将几个shell变量传递给awk命令,然后使用正则表达式在字段上匹配它们。但是,我希望将变量的内容视为正则表达式中的文字。所有这些操作都是针对输入文件的每一行完成的。

所以这个

123^A

可以在任何这些

中找到
123^A|field2|field3
123^A~000^A|field2|field3
000^A~123^A|field2|field3
000^A~123^A~999^A|field2|field3

但这些都不是

123^B|field2|field3
1234^A|field2|field3
123|field2|field3
123~000|field2|field3

不起作用的示例:

read inputfile?'Enter the input file: '
read tackedonvalue?'Enter the value to tack onto each input value: '
read searchfile?'Enter the search file: '
read fieldnum?'Enter the field number to search: '
read delim?'Enter the field delimiter: '

while read -r SEARCHTERM
do awk -F"${delim}" -v a="(^|~)${SEARCHTERM}${tackedonvalue}(~|$)" -v COL="${fieldnum}" '$COL ~ /a/' ${searchfile} >> output_file.txt
done < ${inputfile}
  • “ 123”将是来自输入的$inputfile变量的一行
  • “ ^ A”将是输入中的$tackedonvalue变量

使此示例无法正常工作的原因是$tackedonvalue变量中经常包含^个字符,然后需要对正则表达式进行转义。 (不是在输入中手动转义的选项。)在该变量中可能还输入了其他特殊字符,这些特殊字符也需要转义,因此我不想在每个特殊字符上查找/替换对于每种情况。

我首先尝试过但无法正常工作的另一个示例(与以前相同的输入提示和while read):

awk -F"${delim}" -v a="${SEARCHTERM}" -v b="${tackedonvalue}" -v COL="$fieldnum" '$COL ~ ("(^|~)" a b "(~|$)")' ${searchfile} >> output_file.txt

我认为由于开始和结束锚点,这是行不通的,但是我不知道如何解决这些问题,因此必须使用regex常量(/ pattern /带有正斜杠)。

如果可以在第二个示例中固定锚点,并且将变量内容视为文字,那么这将是另一条路线。

P.S。 -第一篇文章,让我知道要更改/改进/提供的内容。

2 个答案:

答案 0 :(得分:1)

您需要对搜索词中的^进行转义,因为它在正则表达式中具有特殊含义。

SEARCHTERM=${SEARCHTERM//^/\\^}

如果搜索词可能包含在正则表达式中具有特殊含义的其他字符,则需要全部替换。在awk本身中这样做会更容易:

awk -v -F"$delim" search="$SEARCHTERM" -v tacked="$tackedonvalue" -v col="$fieldnum" '
    BEGIN {gsub(/[]*^$]/, "\\&", search); pattern = "(^|~)" search tacked "(~|$)" }
    $col ~ pattern' "$searchfile"

顺便说一句,您不应该使用全部大写的shell变量。习惯上,这些名称是为环境变量保留的。

但是也许您根本不应该使用模式匹配。我认为您可以只拆分~字符上的字段,然后遍历该数组测试是否有任何元素与搜索字符串匹配。

split($col, array, "~");
for (i in array) if (array[i] == (search tacked)) { print; break }

答案 1 :(得分:0)

我不了解awk,但这很容易用perl完成:

$ cat a.txt
123^A|field2|field3
123^A~000^A|field2|field3
000^A~123^A|field2|field3
000^A~123^A~999^A|field2|field3
123^B|field2|field3
1234^A|field2|field3
123|field2|field3
123~000|field2|field3
$ export PAT=123^A
$ export FIELDNUM=0
$ perl  -F'\|' -le "print if \$F[${FIELDNUM}] =~ /(^|~)\Q${PAT}\E(~|$)/" a.txt
123^A|field2|field3
123^A~000^A|field2|field3
000^A~123^A|field2|field3
000^A~123^A~999^A|field2|field3

正则表达式中\Q\E之间的任何字符都会自动转义/忽略任何元字符。