如何使用awk在循环中打印列?

3

我有一个来自某个命令的多列文本输出,想要逐列打印输出,类似于:

#!/usr/bin/ksh

typeset -i i=0
while [[ $i -lt 5 ]]; do
  <command 1> |awk '{print $i}' |<command 2>
  i=$i+1
done

我知道在awk中,$i不能用于指定第i列。这里应该正确使用什么?

假设command 1的输出结果如下:

"abc" "def" "ghi" "jkm"
"123" "456" "789" "0ab"
"erf" "fad" "dae" "kjh"

该值不一定是三个字符长。这里只是举例。

我想依次获取第一列到第四列,以供命令2使用。

2个回答

7
你可能会混淆shell变量$i和awk中第i个字段的$i。你需要使用-v将shell变量的值传递给awk
#!/bin/bash

for i in {1..5}; do 
    <command1> | awk -v i="$i" '{print $i}' | <command2>
done

这将让command2单独处理command1输出的每列内容。

是的,如果 i 从1到5开始,它能正常工作。但是如果我使用原始的while循环,将 i 从0到4迭代,并使用 awk -v i="$i+1" '{print $i}',它又出现了问题。有什么解决方法吗? - Qiang Xu
1
请注意,awk$0 有特殊含义,它代表“整个输入行”,而不是该行中的某个字段。如果你想要 awk 的输出结果是第 1-4 列,你可以将值 1..4 作为 i 的值,或使用 awk -v i=$i '{print $(i+1)}'。但是,按照你的循环写法,将从 4 个字段生成 5 个输出结果,这可能不是一个好主意。 - Jonathan Leffler
@QiangXu 所以只需将 shell 变量 $i 初始化为 1 即可。 - Chris Seymour

4
我不会做你问题中的循环,因为这将执行相同的命令(command 1)n次(例如12次),仅仅是为了提取一个值。如果command 1耗时长,你的脚本就会变慢。即使它不耗时,这也不是好的实践方式,我们不应该这样做。
我建议您只执行cmd1一次,然后将其输出转换为易于传递给commnd2的格式。例如:
OUT1=$(command1||awk '{for (i=1;i<=4;i++)print $i}')

这会将输出变为每列一行,例如:

"abc"
"def"
"ghi"
"jkm"
"123"
"456"
"789"
"0ab"
"erf"
"fad"
"dae"
"kjh"

那么您可以使用循环或其他方法处理变量$OUT1

在awk中也可以调用command2。这取决于要求。如果您不想捕获cmd2的输出,可以执行以下操作:

$(command1||awk '{for (i=1;i<=4;i++)system("command2 "$i)}')

但是,这取决于您的逻辑/要求。

太棒了!是的,这个新设计将极大地提高性能。非常感谢! - Qiang Xu
还有一件事让我困惑,为什么这个 print $i 会在一行中打印第 i 列,而不是打印整个第 i 列? - Qiang Xu
有没有一种方法可以逐列awk输出,并在每列上调用command 2(借助于for循环)?例如,我想先获取"abc"\n"123"\n"erf",并将其用作command 2的输入。之后,再以"def"\n"456"\n"fad"为输入,依此类推。 - Qiang Xu
尝试获取这样的输出,但徒劳无功。肯特,你能给我一个例子吗?这里的要求是仅执行“命令1”一次,并逐列打印其输出。 - Qiang Xu
好的,我尝试用一个例子来解释。邓辉 ^_^ - Kent
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接