awk将双引号字符串视为一个标记,并忽略其间的空格

时间:2011-07-08 03:12:58

标签: bash unix awk

数据文件 - data.txt:

ABC "I am ABC" 35 DESC
DEF "I am not ABC" 42 DESC

cat data.txt | awk '{print $2}'

将导致“I”而不是引用的字符串

如何制作awk以便忽略引号中的空格并认为它是一个单一的标记?

7 个答案:

答案 0 :(得分:8)

另一种选择是使用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"

答案 1 :(得分:7)

是的,这可以在awk中很好地完成。没有任何严重的黑客攻击很容易获得所有领域。

(此示例适用于The One True Awk和gawk。)

{
  split($0, a, "\"")
  $2 = a[2]
  $3 = $(NF - 1)
  $4 = $NF
  print "and the fields are ", $1, "+", $2, "+", $3, "+", $4
}

答案 2 :(得分:5)

试试这个:

$ cat data.txt | awk -F\" '{print $2}'
I am ABC
I am not ABC

答案 3 :(得分:3)

此问题的最佳答案仅适用于带有单引号字段的行。当我发现这个问题时,我需要一些可以用于任意数量的引用字段的东西。

最终我遇到了an answer by Wintermute in another thread,他为这个问题提供了一个很好的通用解决方案。我刚修改它以删除引号。请注意,在运行以下程序时,您需要使用-F\"调用awk。

BEGIN { OFS = "" } {
    for (i = 1; i <= NF; i += 2) {
        gsub(/[ \t]+/, ",", $i)
    }
    print
}

这可以通过观察当你用“-character”分隔时数组中的每个其他元素都在引号内部,因此它用逗号代替除了引号之外的空格。

然后,您可以轻松地链接另一个awk实例来执行您需要的任何处理(只需再次使用字段分隔符开关,-F,)。

请注意,如果引用第一个字段,这可能会中断 - 我还没有测试过。但是,如果确实如此,则应该很容易通过添加if语句来从2开始而不是1,如果该行的第一个字符是“。

答案 4 :(得分:2)

我把一个将$ 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]
}

希望它有所帮助。

答案 5 :(得分:0)

好的,如果你真的想要所有三个领域,你可以得到它们,但它需要很多管道:

$ 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

通过最后一根烟斗你可以得到所有三个字段来做任何你喜欢的事情。

答案 6 :(得分:0)

这是我最终工作的东西,对我的项目更通用。 请注意,它不使用awk。

http = 0.0.0.0:8080

哪个输出:

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)"