在 awk 中使用 shell 变量

在 awk 中使用 shell 变量

这是我的脚本(用于查找包含指定模式的文件):

find . -type f \
    -exec awk -v vawk="$1" '/'"$vawk"'/ {c++} c>0 { print ARGV[1]; exit 0 } END { if (! c) {exit 1}}' \{\} \;

我想使用带有参数的脚本 §:

MyScript.sh pattern

我的问题是我无法将$1变量放入awk.

当我尝试调试我的脚本时

bash -x MyScript.sh pattern

这是输出:

+ find . -type f -exec awk -v vawk=pattern '// {c++} c>0 {print ARGV[1] ; exit 0 } END { if (! c) {exit 1}}' '{}' ';'

$vawk变量似乎为空。

任何想法?

答案1

您似乎混淆了 awk 变量和 shell 变量。 awk -v vawk="$1"创建一个awk变量名为vawk,但您正在尝试使用句法 ($vawk)。这不起作用,因为 shell 没有名为 的变量vawk。我想你想要的是

awk -v vawk="$1" '$0 ~ vawk { c++ } # ...'
#                      ^ awk variable syntax

答案2

转载自现在关闭为复制问题因为它包含有关 awk 变量传递限制的警告,这可能会很有用。

shell 变量就是:A多变的。如果你想把它变成一个awk变量,您需要一个语法,例如:

awk -v x="$x" '$2 == x {print $1}' infile

或者

awk '$2 == x {print $1}' x="$x" infile

然而,它们遇到了一个问题:转义序列在其中被扩展。

另外,对于 GNU awk4.2 或更高版本,如果$x以 开头@/并以 结尾/,则将其视为正则表达式类型的变量)。

因此,例如如果 shell 变量包含两个字符反斜杠n,awk 变量最终将包含新队字符并且对于 gawk 4.2+,如果它包含@/foo/,则 awk 变量将包含foo并且类型为regexp。更糟糕的是@/(xxxxx){1,20000}/,gawk 会占用一个 CPU 数小时或直到内存耗尽,试图编译该正则表达式,从而使其成为某种形式的 DoS 漏洞。

另一种方法(但与 for 一样-v需要 POSIX awk 或 nawk(与 Solaris 中仍然使用的 1970 年代的 awk 相反/bin/awk))是使用环境变量:

x="$x" awk '$2 == ENVIRON["x"] {print $1}' infile

另一种方法(仍然使用较新的 awks)是在 awk 中使用 ARGV 数组:

awk -- 'BEGIN {x = ARGV[1]; delete ARGV[1]}
  $2 == x {print $1}' "$x" infile

还要注意,无论你使用ARGV/ ENVIRON/-vvar=value参数,相应的字符串都将被视为数字串如果它的形状像一个数字(可识别的数字格式的范围随实现而变化)。

这很重要,因为在上面的例子中,如果是或,$2 == ENVIRON["VAR"]它将是一个字符串比较,但如果是或(或者可能是, 取决于实现和版本),它将是一个数字比较,假设也看起来是数字。因此、和都被认为是平等的。$VARfoo1f21e21.1inf0xffawk$210.0e11001e2

正在做:

awk 'BEGIN {var = "" ENVIRON["VAR"]}'

确保var awk变量始终被视为字符串,即使$VARshell 变量看起来像数字。

awk 'BEGIN {var = 0 + ENVIRON["VAR"]}'

将其转换为数字(至少其前导部分可以解释为数字)。


strcoll()与某些实现进行比较(如 POSIX 所要求的),也就是说,如果和具有相同的排序顺序,a == b则其中一个ab或两个都是字符串将返回 true 。ab

相关内容