数据文件 – data.txt:
ABC "I am ABC" 35 DESC DEF "I am not ABC" 42 DESC
cat data.txt | awk '{print $2}'
将导致“我”,而不是被引用的string
如何使awk忽略引号内的空格,并认为它是一个单一的标记?
是的,这可以在awk中很好地完成。 很容易得到所有的领域没有任何严重的黑客攻击。
(这个例子在一个真正的Awk和gawk中都有效。)
{ split($0, a, "\"") $2 = a[2] $3 = $(NF - 1) $4 = $NF print "and the fields are ", $1, "+", $2, "+", $3, "+", $4 }
尝试这个:
$ cat data.txt | awk -F\" '{print $2}' I am ABC I am not ABC
我已经把一个将$ 0重新分割成一个名为B的数组的函数一起缩小了。双引号之间的空格不作为字段分隔符。 适用于任何领域,混合引用和不引用的字段。 开始:
#!/usr/bin/gawk -f # Resplit $0 into array B. Spaces between double quotes are not separators. # Single quotes not handled. No escaping of double quotes. function resplit( a, l, i, j, b, k, BNF) # all are local variables { l=split($0, a, "\"") BNF=0 delete B for (i=1;i<=l;++i) { if (i % 2) { k=split(a[i], b) for (j=1;j<=k;++j) B[++BNF] = b[j] } else { B[++BNF] = "\""a[i]"\"" } } } { resplit() for (i=1;i<=length(B);++i) print i ": " B[i] }
希望能帮助到你。
这个问题的最佳答案只适用于带有单引号字段的行。 当我发现这个问题时,我需要一些可以用于任意数量的引用字段的东西。
最后,我在另一个线程中找到了Wintermute的一个答案 ,他为这个问题提供了一个很好的一般化的解决方案。 我刚刚修改它删除引号。 请注意,在运行下面的程序时,需要用-F\"
调用awk。
BEGIN { OFS = "" } { for (i = 1; i <= NF; i += 2) { gsub(/[ \t]+/, ",", $i) } print }
这是通过观察数组中的每个其他元素在用“-character”分隔的引号内部的,因此它用逗号代替不用引号括起来的空格。
然后,您可以轻松链接另一个awk实例,以执行您所需的任何处理(只需再次使用字段分隔符开关-F,
)即可。
请注意,如果第一个字段被引用,这可能会中断 – 我还没有测试过。 如果是这样的话,应该很容易通过添加一个if语句来从2开始,而不是1,如果该行的第一个字符是“。
另一种方法是使用FPAT
变量,它定义了描述每个字段内容的正则表达式。
将这个AWK脚本保存为parse.awk
:
#!/bin/awk -f BEGIN { FPAT = "([^ ]+)|(\"[^\"]+\")" } { print $2 }
使用chmod +x ./parse.awk
使其可执行,并将数据文件解析为./parse.awk data.txt
:
"I am ABC" "I am not ABC"
好吧,如果你真的想要所有的三个领域,你可以得到他们,但需要很多的管道:
$ cat data.txt | awk -F\" '{print $1 "," $2 "," $3}' | awk -F' ,' '{print $1 "," $2}' | awk -F', ' '{print $1 "," $2}' | awk -F, '{print $1 "," $2 "," $3}' ABC,I am ABC,35 DEF,I am not ABC,42
通过最后一个管道,你有三个领域做任何你想做的事情。
这就像我最终得到的工作,这是我的项目更通用。 注意它不使用awk。
someText="ABC \"I am ABC\" 35 DESC '1 23' testing 456" putItemsInLines() { local items="" local firstItem="true" while test $# -gt 0; do if [ "$firstItem" == "true" ]; then items="$1" firstItem="false" else items="$items $1" fi shift done echo "$items" } count=0 while read -r valueLine; do echo "$count: $valueLine" count=$(( $count + 1 )) done <<< "$(eval putItemsInLines $someText)"
哪些产出:
0: ABC 1: I am ABC 2: 35 3: DESC 4: 1 23 5: testing 6: 456