awk在regexp中将变量视为文字

mnemlml8  于 2023-06-25  发布在  其他
关注(0)|答案(2)|浏览(83)

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

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

我认为这并不起作用,因为开始和结束锚,但我不知道如何修复这些,所以不得不使用正则表达式常量(/pattern/带正斜杠)。
如果第二个例子的锚点是固定的,并且变量内容被视为文字,那么这将是另一种途径。
P.S. -第一篇文章,所以让我知道需要改变/改进/提供什么。

qfe3c7zg

qfe3c7zg1#

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

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

vsmadaxz2#

我不了解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之间的任何内容都会自动转义/忽略任何元字符。

相关问题