13

我有以下脚本

awk '{printf "%s", $1"-"$2", "}' $a >> positions;

其中$a存储文件的名称。我实际上是将多个列值写入一行。但是,只有当我不在最后一行时,我才想打印一个逗号。

4

6 回答 6

22

单程方法:

cat "$a" | # look, I can use this in a pipeline! 
  awk 'NR > 1 { printf(", ") } { printf("%s-%s", $1, $2) }'

请注意,我还简化了字符串格式。

于 2013-01-25T09:24:16.920 回答
13

享受这个:

awk '{printf t $1"-"$2} {t=", "}' $a >> positions

是的,第一眼看起来有点棘手。所以我会解释一下,首先让我们为了printf清楚print起见:

awk '{print t $1"-"$2} {t=", "}' file

看看它做了什么,例如,对于具有以下简单内容的文件:

1 A
2 B
3 C
4 D

所以它将产生以下内容:

 1-A
 , 2-B
 , 3-C
 , 4-D

诀窍是前面的t变量在开始时为空。该变量将{t=...}仅在显示后的下一步处理中设置{print t ...}。因此,如果我们 ( awk) 继续迭代,我们将得到所需的序列。

于 2014-11-18T10:58:20.820 回答
6

我会通过在运行脚本之前找到行数来做到这一点,例如使用 coreutils 和 bash:

awk -v nlines=$(wc -l < $a) '{printf "%s", $1"-"$2} NR != nlines { printf ", " }' $a >>positions

如果您的文件只有 2 列,则以下 coreutils 替代方案也适用。示例数据:

paste <(seq 5) <(seq 5 -1 1) | tee testfile

输出:

1   5
2   4
3   3
4   2
5   1

现在用换行符替换制表符,paste可以轻松地将日期组合成所需的格式:

 <testfile tr '\t' '\n' | paste -sd-,

输出:

1-5,2-4,3-3,4-2,5-1
于 2013-01-25T08:26:33.003 回答
4

您可能认为 awk 的 ORS 和 OFS 是处理此问题的合理方法:

$ awk '{print $1,$2}' OFS="-" ORS=", " input.txt

但这会导致最终的 ORS,因为输入在最后一行包含换行符。换行符是一个记录分隔符,因此从 awk 的角度来看,输入中有一条空的最后一条记录。您可以通过一些技巧来解决这个问题,但由此产生的复杂性消除了单线的优雅。

所以这是我对此的看法。由于您说您正在“编写多个列值”,因此使用 ORS 和 OFS 可能会导致问题。所以我们可以完全通过格式化来实现所需的输出。

$ cat input.txt
3 2
5 4
1 8
$ awk '{printf "%s%d-%d",t,$1,$2; t=", "} END{print ""}' input.txt
3-2, 5-4, 1-8

这类似于 Michael 和 rook 的单遍方法,但它使用单遍printf并正确使用格式字符串进行格式化。

这可能会比 Michael 的解决方案执行得好到可以忽略不计,因为分配应该比测试占用更少的 CPU,并且明显优于任何多通道解决方案,因为文件只需要读取一次。

于 2018-03-10T18:47:29.867 回答
1

这是一种更好的方法,无需借助 coreutils:

awk 'FNR==NR { c++; next } { ORS = (FNR==c ? "\n" : ", "); print $1, $2 }' OFS="-" file file
于 2013-01-25T08:58:37.820 回答
0
awk '{a[NR]=$1"-"$2;next}END{for(i=1;i<NR;i++){print a[i]", " }}' $a > positions
于 2013-01-25T09:26:01.467 回答