shell如何为awk生成输入

时间:2016-12-01 21:37:09

标签: linux bash shell awk

假设我有一个包含以下内容的文件:

1,2,3,4

我可以使用awk像这样处理该文件;

awk -v FS="," '{print $1}' file1

此外,我可以使用Here String调用awk,这意味着我从stdin中读取:

awk -v FS="," '{print $1}' <<<"9,10,11,12"

命令1产生结果1,命令2按预期产生9。

现在说我有第二个文件2:

4,5

如果我用awk后续解析这两个文件:

awk -v FS="," '{print $1}' file1 file2

我明白了:

1
4

正如所料。

但是,如果我正在混合stdin 读取文件的读取,那么我从stdin读取的内容将被忽略,只有文件中的内容会按顺序处理:

awk -v FS="," '{print $1}' file1 file2 <<<"9,10,11,12"
awk -v FS="," '{print $1}' file1 <<<"9,10,11,12" file2
awk -v FS="," '{print $1}' <<<"9,10,11,12" file1 file2

所有三个命令都会产生:

1
4

这意味着来自stdin的内容只会被丢弃。现在shell在做什么?

有趣的是,如果我将命令3更改为:

awk -v FS="," '{print $1}' <<<"9,10,11,12",file1,file2

我只是得到9,这是有意义的,因为file1 / 2只是stdin的两个字段。但那为什么呢?

awk -v FS="," '{print $1}' <<<"9,10,11,12" file1 file2

未扩展为

awk -v FS="," '{print $1}' <<<"9,10,11,12 file1 file2"

还会产生结果9

为什么来自stdin的内容会被忽略?对命令1和2也出现了同样的问题。在这里做了什么shell?

我尝试了以下命令:GNU bash,版本4.2.53(1)-release

1 个答案:

答案 0 :(得分:1)

文件的标准输入和输入不能很好地混合在一起。此行为不是awk独有的,您可以在许多命令行应用程序中找到它。如果你这样想是合乎逻辑的:

需要逐个处理文件。消费应用程序无法控制STDIN后面的输入何时开始和停止。看echo a,b,c | awk -F, '{print $1}' file1 file2。需要以什么顺序读取传入的“文件”?当您考虑何时需要重置FNRFILENAME应该是什么时,很明显很难做到这一点。

您可以玩的一个技巧是让awk(或任何其他程序)从shell生成的文件描述符中读取。 awk -F, '{print $1}' file1 <(echo 4,5,6) file2将首先完成您的预期。

这里发生的是,使用<(...)语法(例如:/proc/self/fd/11)创建了正确的文件描述符,并且读取程序可以将其视为文件。这是第二个参数,所以它是第二个文件。 FNRFILENAME都清楚它们应该是什么。