2

$file是一个 csv(制表符分隔),有 59 列和 64 行。第 1 列始终是字符串,而 cols 2+ 始终是整数(当值为 时除外NULL)。

cat ${file} | while read line 
    do awk -F'\t' '{ for (i=2; i<=NF; i++) print $1 "\t" $i "." }';
    done;

输出:

Excellent   .
Good    .
…

然而切换$i$2工作:

Excellent   29.
Good    7.
…

为什么??

编辑

#lines 1 & 2 from data.csv (columns truncated for brevity):
Excellent   29  54  47  46  38  22  50
Good    7   14  27  24  26  36  20

#reform.sh
file=$1;
awk -F'\t' '{ for (i=2; i<=NF; i++) print $1 "\t" $i; }' ${file};

仍然像以前一样表现/返回。

解决方案

批准的答案确实提供了 AWK 的正确输出。重新启动我的终端应用程序后,脚本按所述执行。我无法确定终端应用程序问题的原因。

4

2 回答 2

7

我认为你错了。您拥有的脚本不会输出任何智能(a),因为当您尝试将每一行读入$line时,您实际上并没有将它们提供给awk.

您可以通过以下方式摆脱多余(和不正确)的循环:

awk -F'\t' '{ for (i=2; i<=NF; i++) print $1 "\t" $i "." }' ${file}

如以下成绩单所示:

pax> echo 'A 1 2
...> B 3 4
...> C 5 6' >qq.in

pax> cat qq.in
A 1 2
B 3 4
C 5 6

pax> awk -F' ' '{ for (i=2; i<=NF; i++) print $1 " " $i "." }' qq.in
A 1.
A 2.
B 3.
B 4.
C 5.
C 6.

如您所见(尽管我使用的是空格而不是制表符),这会为您提供所需的输出。


针对您声称它仍然无法正常工作的说法,恐怕我不得不提出不同意见。以下成绩单(带有标签)表明它可以像宣传的那样工作。

pax> cat qq.in
Excellent   29      54      47      46      38      22      50
Good        7       14      27      24      26      36      20

pax> awk -F'\t' '{ for (i=2; i<=NF; i++) print $1 "\t" $i; }' qq.in
Excellent   29
Excellent   54
Excellent   47
Excellent   46
Excellent   38
Excellent   22
Excellent   50
Good        7
Good        14
Good        27
Good        24
Good        26
Good        36
Good        20

如果它实际上不在您的环境中工作,那是一个不同的问题。您可能有越野车awk或任何其他原因导致它失败。

首先,弄清楚awk您使用的是什么版本和操作系统,例如:

awk --version
uname -a

(a):它确实输出了一些东西,但几乎可以肯定不是你所期望的。让我们实际看看现实中发生了什么。考虑以下与您的原件类似的成绩单:

pax> ( echo 1; echo 2; echo 3 ) | while read line ; do
...>     awk '{print "[" $0 "]"}'
...> done
[2]
[3]

现在这看起来很奇怪,它似乎正在丢弃第一行。

造成这种情况的原因是while和之间的脱节awk。从标准输入读取第一行并将其while分配给$line,然后执行该do..done部分的主体。

该主体是awk没有输入文件的,因此它从标准输入中获取输入!

这意味着它将“吸收”您的标准输入流的其余部分并对其进行处理。

然后,它将返回到while循环,但由于标准输入上没有更多数据,它将完成。最好用以下方式说明:

pax> ( echo 1; echo 2; echo 3 ) | while read line ; do
...>     echo "read: $line"
...>     awk '{print "awk:  " $0}'
...> done
read: 1
awk:  2
awk:  3

如果您实际上whileawk与下面的部分连接起来,echo "$line" |您会看到它正常工作:

pax> ( echo 1; echo 2; echo 3 ) | while read line ; do
...>     echo "$line" | awk '{print "[" $0 "]"}'
...> done
[1]
[2]
[3]

当然,将您的输入分成几行并一次发送awk一条是没有意义的,因为awk它完全能够一次处理多行。

所以这个答案的第一个代码块中显示的单行awk命令仍然是一种更好的方法。

于 2012-10-09T00:35:34.677 回答
2

你可以做

awk -F$'\t' '{ for (i=2; i<=NF; i++) print $1 "\t" $i "." }' FILE

而不是所有不需要的管道。

于 2012-10-09T00:28:42.893 回答