样本数据
wolf@linux:~$ awk {print} file.txt
a b
b c
c d
wolf@linux:~$
由于数据非常小,因此很容易做到这一点。
wolf@linux:~$ awk 'BEGIN {print " " 1 " " 2} {print NR,$0}' file.txt
1 2
1 a b
2 b c
3 c d
wolf@linux:~$
对于更大的数据有类似的解决方案吗?我正在考虑使用类似for loop
on BEGIN {print " " 1 " " 2}
part 的东西,而不是手动打印标题
答案1
该BEGIN
部分在打开任何输入文件之前执行,因此运行 a for loop
There 不会有任何好处,因为输入的第一行尚未被读取,因此您不知道有多少字段要循环。除非你添加一个getline
,但这完全是另一堆蠕虫(参见http://awk.freeshell.org/AllAboutGetline)。
我将awk
创建字段内容,然后将column
其格式化为间距,例如:
$ awk '
NR==1 { for (i=1; i<=NF; i++) printf " %s", i; print "" }
{ print NR, $0 }
' file | column -s' ' -t
1 2
1 a b
2 b c
3 c d
如果您的输入文件字段之间可能有多个空格或制表符,则只需将 awk 脚本的最后一行从 更改{ print
为{ $1=$1; print
.
答案2
我们可以使用 groff 包装器生成表tbl
,它生成 groff 代码以根据所需的架构生成表。
在这里,根据数据,我们动态生成 tbl 实用程序的代码,该代码将使用 awk 实用程序生成 groff 排版实用程序的代码:
< file \
awk '
BEGIN {
OFS = "@"
print ".TS"
print "box,tab(", ");"
}
!NF {next}
NR==1 {
fx(" ", "c", "c", ".")
fx(OFS)
}
{ $1 = NR OFS $1 };1
END { print ".TE" }
function fp(str, sep) {
printf "%s%s", sep, str
}
function fx(sep, a, b, c, i) {
fp(a)
for (i=1; i<=NF; i++)
fp(b""?b:i, sep)
fp("\n", c)
}
' - | tbl - | groff -Tascii | grep .
输出:
+----------+
| 1 2 |
|1 A B |
|2 B C |
|3 C D |
+----------+
答案3
您可以使用 for 循环来迭代字段。 NR 是当前行号,NF 是该特定行上的字段数。
{ printf ("%4d", NR);
for (f = 1; f <= NF; ++f) printf (" %-6s", $f);
printf ("\n");
}
对于标题,您需要等待第一行才能发现需要标记多少列。所以这就是前前面的代码。请注意,它将 f 本身打印为标签,而不是代表字段内容的 $f。
NR == 1 { printf ("%4d", NR);
for (f = 1; f <= NF; ++f) printf (" %-6s", f);
printf ("\n");
}
您需要找到最大字段宽度以保持对齐。每个 %-6 表示“一个字符串字段,左对齐,并用空格填充最多 6 个字符”。
编辑:对于更高级的版本,您可以将所有数据存储在二维数组中,按 [NR, NF] 索引,并将它们输出到 END 块中。然后你还可以做两件事:
(1) 对于每一列,找到任何单元格的最大宽度,并使用该列的实际宽度修复 %-10s 格式。
(2) 对于每一列,如果其全部为数值,则修复其 %s 以右对齐值。