我在“test.txt”文件中有一个字符串:
207.46.13.136 - - [22/Jan/2019:03:56:21 +0330] "GET /product/30649?model=60398 HTTP/1.1" 200 41198 "-" "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)" "-"
我执行了:
grep 'GET /product/*' test.txt | awk -F "/" '{ if ( "${#5}" -lt 6 ) {print $5} } '
所以它应该输出$5
长度小于 6 的所有字符串。
我预计不会有输出,因为 my 的长度$5
是 22 ( 30649?model=60398 HTTP
) 但它还是输出了该字符串。
编辑:我发现 的长度"30649?model=60398 HTTP"
是 0!我更困惑了。
发生了什么?
答案1
您awk
在这里混淆了 shell 和语法。
sh
(或bash
) 和awk
是两种不同语言的两个解释器,彼此无关。
的语法awk
非常类似于 C。
在 中awk
,变量是用 引用的var
,$var
与 shell 中不同,$
inawk
是一个一元运算符,用于检索输入字段的值(如果应用于 0,则检索完整记录)。$ (3 + 3)
例如检索第 6 个字段的值。 in 中的字符串常量内部没有变量插值awk
,更不用说运算符的解释,无论它是一元-
还是。+
$
所以 in 中awk
,"${#5}"
只是具有文字值 的字符串常量${#5}
。
"${#5}" -lt
,与应用于该字符串和变量的"string" - lt
二元运算符相同。因为它是算术运算符,所以两个操作数都转换为数字。由于两者都以看起来像产生 的数字开头,所以都是 0。-
lt
0 - 0
然后使用(不可见的)串联运算符。在x y
、x
和中,y
它们被转换为字符串并连接起来产生一个新字符串。这"${#5}" -lt 6
就是字符串("${#5}" - lt) 6
的结果"06"
。
$ gawk 'BEGIN{result = "${#5}" -lt 6; print typeof(result) ": " result}'
string: 06
这用作if
true 是非 0 数字或非空字符串的条件,所以这里我们总是得到真的因为"06"
是一个非空字符串。
这里正确的awk
语法是:
awk -F "/" '{ if (length($5) < 6) print $5 }'
或者使用更规范的<condition> {<action>}
图案:
awk -F/ 'length($5) < 6 {print $5}'
另请注意,grep 'GET /product/*'
查找GET /product
后跟任意数量(包括 0)的/
字符,因此它在功能上等同于grep 'GET /product'
.awk
作为 的超集grep
,您通常也不需要将它们通过管道连接在一起。所以在这里:
awk -F/ 'index($0, "GET /product/") && length($5) < 6 {print $5}'
index($0, "string")
在string
完整记录中定位 ( )$0
相当于grep -F 'GET /product/'
.另请参见/regexp/
( 的缩写$0 ~ /regexp/
) 的等效项grep -E regexp
。