这是我的脚本(用于查找包含指定模式的文件):
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 awk
4.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
/-v
或var=value
参数,相应的字符串都将被视为数字串如果它的形状像一个数字(可识别的数字格式的范围随实现而变化)。
这很重要,因为在上面的例子中,如果是或,$2 == ENVIRON["VAR"]
它将是一个字符串比较,但如果是或(或者可能是, 取决于实现和版本),它将是一个数字比较,假设也看起来是数字。因此、和都被认为是平等的。$VAR
foo
1f2
1e2
1.1
inf
0xff
awk
$2
10.0e1
100
1e2
正在做:
awk 'BEGIN {var = "" ENVIRON["VAR"]}'
确保var
awk
变量始终被视为字符串,即使$VAR
shell 变量看起来像数字。
awk 'BEGIN {var = 0 + ENVIRON["VAR"]}'
将其转换为数字(至少其前导部分可以解释为数字)。
或strcoll()
与某些实现进行比较(如 POSIX 所要求的),也就是说,如果和具有相同的排序顺序,a == b
则其中一个a
或b
或两个都是字符串将返回 true 。a
b