为什么我在awk的printf中以$ 0获得奇怪的输出?

时间:2015-01-25 01:05:07

标签: bash awk printf

输入正在跟随

Title: Aoo Boo

Author: First Last

我正在尝试输出

Aoo Boo, First Last, "

使用像这样的awk

awk 'BEGIN { FS="[:[:space:]]+" }
/Title/ { sub(/^Title: /,""); t = $0; } # save title
/Author/{ sub(/^Author: /,""); printf "%s,%s,\"\n", t, $0} 
' t.txt

但输出就像是“irst Last。基本上它从句子的开头打印出所有内容。

但如果我将$ 0更改为$ 2,则输出为预期值Boo,Last,"

为什么不正确?什么是正确的方法?

2 个答案:

答案 0 :(得分:2)

如果要使用Unix实用程序,则需要删除文本文件中的Windows行结尾。

如果你很幸运,你会发现你安装了dos2unix程序,而你只需要这样做:

dos2unix t.txt

如果没有,您可以使用tr

执行此操作
tr -d '\r' < t.txt > new_t.txt

作为参考,正在发生的事情是Windows文件在每一行的末尾都有\r\n(实际上, CR 控制代码后跟 NL 控制代码)。在Linux上,行以\n结束,因此\r是数据的一部分;当你打印出来时,终端将其解释为“回车”,它将光标移动到当前行的开头,而不是前进到下一行。由于t的值以\r结尾,因此以下文字将覆盖t的值。

它适用于$2,因为您已重新分配FS以包含[:space:];字段分隔符的定义比awk默认值更慷慨,因为它包含\r\f,它们都不是默认字段分隔符。因此,$2不包含\r,但$0包含{。}}。

答案 1 :(得分:0)

这假设标题或名称中没有冒号......

awk -F': *' '
  $1=="Title" {
    sub(/[^[:print:]]/,"");
    t=$2;
  }
  $1=="Author" {
    sub(/[^[:print:]]/,"");
    printf("%s, %s\n", t, $2);
  }
' inputfile.txt

这可以通过查找标题并将其存储在变量中,然后找到作者并将其用作触发器来根据您的格式打印所有内容。您可以根据需要更改格式。

如果线上有额外的冒号,可能会破坏,因为冒号用于分割字段。如果您的输入与您的示例不符,它也可能会中断。

在这个例子中,最重要的可能是sub(...)函数,它们剥离了不可打印的字符,比如rici注意到的回车符。正则表达式[^[:print:]]匹配“可打印”字符,回车符不是。如果这些脚本存在, sub 会将它们遗忘,但如果不存在则不应该受到伤害。