![awk 将 TSV 表转换为网格表](https://linux22.com/image/178634/awk%20%E5%B0%86%20TSV%20%E8%A1%A8%E8%BD%AC%E6%8D%A2%E4%B8%BA%E7%BD%91%E6%A0%BC%E8%A1%A8%20.png)
我想将以制表符作为分隔符的文本表(即基本上是 TSV 文件)转换为所有边框(内部和外部)上都有线条且文本换行的网格表。
下面是输入
TrackId peerId Cause Count
ESS_RSM pra4.pra.pnc100.tpp240.6pppsetwork.prg 40009 Response is not received from server 1401
ESS_RSM pra5.pra.pnc100.tpp240.6pppsetwork.prg 40009 Response is not received from server 1398
ESS_RSM pra3.pra.pnc100.tpp240.6pppsetwork.prg 40009 Response is not received from server 1347
ESS_RSM pra1.pra.pnc100.tpp240.6pppsetwork.prg 40009 Response is not received from server 1412
ESS_RSM pra2.pra.pnc100.tpp240.6pppsetwork.prg 40009 Response is not received from server 1355
ESS_RSM pra6.pra.pnc100.tpp240.6pppsetwork.prg 40009 Response is not received from server 1416
大片的空白是制表符; “未从服务器收到响应”中的空白是空格。输出应如下所示:
┌────────┬────────────────────────────────────────┬────────────────────────────┬────────┐
│TrackId │ peerId │ Cause │ Count │
├────────┼────────────────────────────────────────┼────────────────────────────┼────────┤
│ESS_RSM │ pra4.pra.pnc100.tpp240.6pppsetwork.prg │ 40009 Response is not │ 1,401 │
│ │ │ received from server │ │
├────────┼────────────────────────────────────────┼────────────────────────────┼────────┤
│ESS_RSM │ pra5.pra.pnc100.tpp240.6pppsetwork.prg │ 40009 Response is not │ 1,398 │
│ │ │ received from server │ │
├────────┼────────────────────────────────────────┼────────────────────────────┼────────┤
│ESS_RSM │ pra3.pra.pnc100.tpp240.6pppsetwork.prg │ 40009 Response is not │ 1,347 │
│ │ │ received from server │ │
├────────┼────────────────────────────────────────┼────────────────────────────┼────────┤
│ESS_RSM │ pra1.pra.pnc100.tpp240.6pppsetwork.prg │ 40009 Response is not │ 1,412 │
│ │ │ received from server │ │
├────────┼────────────────────────────────────────┼────────────────────────────┼────────┤
│ESS_RSM │ pra2.pra.pnc100.tpp240.6pppsetwork.prg │ 40009 Response is not │ 1,355 │
│ │ │ received from server │ │
├────────┼────────────────────────────────────────┼────────────────────────────┼────────┤
│ESS_RSM │ pra6.pra.pnc100.tpp240.6pppsetwork.prg │ 40009 Response is not │ 1,416 │
│ │ │ received from server │ │
└────────┴────────────────────────────────────────┴────────────────────────────┴────────┘
或者可能
TrackId │ peerId │ Cause │ Count │
────────┼────────────────────────────────┼──────────────────────────────────────┼─────────┤
│ pra4.pra.pnc100.tpp240.6pppset │ 40009 Response is not received from │ │
ESS_RSM │ work.prg │ server │ 1,401 │
────────┼────────────────────────────────┼──────────────────────────────────────┼─────────┤
│ pra5.pra.pnc100.tpp240.6pppset │ 40009 Response is not received from │ │
ESS_RSM │ work.prg │ server │ 1,398 │
────────┼────────────────────────────────┼──────────────────────────────────────┼─────────┤
│ pra3.pra.pnc100.tpp240.6pppset │ 40009 Response is not received from │ │
ESS_RSM │ work.prg │ server │ 1,347 │
────────┼────────────────────────────────┼──────────────────────────────────────┼─────────┤
│ pra1.pra.pnc100.tpp240.6pppset │ 40009 Response is not received from │ │
ESS_RSM │ work.prg │ server │ 1,412 │
────────┼────────────────────────────────┼──────────────────────────────────────┼─────────┤
│ pra2.pra.pnc100.tpp240.6pppset │ 40009 Response is not received from │ │
ESS_RSM │ work.prg │ server │ 1,355 │
────────┼────────────────────────────────┼──────────────────────────────────────┼─────────┤
│ pra6.pra.pnc100.tpp240.6pppset │ 40009 Response is not received from │ │
ESS_RSM │ work.prg │ server │ 1,416 │
────────┴────────────────────────────────┴──────────────────────────────────────┴─────────┘
我尝试了下面的代码,但输出不是我想要的。
awk '{print "<table>"} {print "<tr>"; for(i=1;i<=NF;i++) print "|" $i "|";print "|"} END {PRINT "|"}' file
答案1
使用一些古老的 Unix 实用程序,
#!/bin/sh
{
printf '%s\n' '' .TS 'allbox;LLLL,LLLR.'
awk -v sq="'" '
BEGIN { FS = OFS = "\t"; fmt = "%" sq "d" }
NR==1 { print }
NR>1 {
print $1, "T{"
print $2
print "T}", "T{"
print $3
print "T}", sprintf(fmt, $4)
}
' "$@"
printf '%s\n' .TE '.pl 0'
} | tbl | nroff 2> /dev/null
解释:
nroff
是古老的 Unix 文本处理器。例如,它将采取
作为输入,并产生Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
作为输出。Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
tbl
nroff
是一个支持(你猜对了)表格生成的前端。.TS
是“表开始”。allbox
相当明显:在每个单元格周围画一个框。LLLL
表示第一行中的所有单元格都是左对齐的;LLLR
意味着第四个单元格对于所有后续行都是右对齐的。我想这就是您从示例输出中想要的结果。-v sq="'"
创建一个名为的变量,sq
其值为单引号。这是在 awk 程序中使用单引号的方法之一,建议在GNU Awk 用户指南。- 设置
FS
为制表符,因为输入是 TSV。设置OFS
为制表符,因为这是所tbl
期望的(默认情况下)。 fmt = "%" sq "d"
设置fmt
为%'d
,可与 一起使用来[s]printf
输出带有千位分隔符的整数。 (我假设你想要这个,因为你展示了它。)- 不加修改地传递第一行(标题)。
- 对于所有其他行(数据),使用
T{
和T}
标记$2
进行$3
文本换行。 (我假设您只需要第二列和第三列,因为第一列和第四列仅包含短字符串。)打印 的值,$4
每三个数字插入一个逗号。 .TE
是“桌尾”。.pl
是页面长度。这是一个拼凑的东西。默认情况下,nroff
将用空行填充其输出,以使整体输出成为 66 行的倍数。通过将页面长度设置为零,我们可以抑制这种情况。- 上述 (
printf
,awk
和printf
) 的输出通过管道输送到tbl
和nroff
。 - 尽管标准输出是合理的,但我还是遇到了很多出现错误消息的问题,所以我将 stderr 发送到了 bitbucket。如果你得到奇怪的结果,你应该做的第一件事就是摆脱 stderr 重定向并查看错误消息(尽管它们可能不是很有帮助)。
指示:
- 将上面的代码放入一个文件中。例如,调用它
gman
。 - 做
使其可执行。$ chmod +x gman
- 如果您的数据位于文件中(例如,名为
shap
),请执行以下操作
您可能希望将输出重定向到文件:$ ./gman shap
$ ./gman shap > grid_table
- 如果您在第一列中获取所有数据,则意味着您的输入文件中实际上没有制表符(只是空格)。编辑它以用制表符替换空白(空格)。
- 如果您的数据是由其他程序生成/产生的,例如数据库查询,您可以这样做
(然后可选$ db_query > tmp $ ./gman tmp
rm tmp
,如果您不需要它做其他任何事情),或者只是$ db_query | ./gman
- 如果您将文件移动(或复制)
gman
到搜索路径中的目录,则只需键入gman
(无需./
)。有一个 很多有关于此的文档;如果你搜索的话很容易找到。
例如,对于问题中显示的输入,我得到
┌───────────┬─────────────────────────────────┬───────────────┬───────┐
│ TrackId │ peerId │ Cause │ Count │
├───────────┼─────────────────────────────────┼───────────────┼───────┤
│ESS_RSM │ pra4.pra.pnc100.tpp240.6pppset‐ │ 40009 Re‐ │ 1,401 │
│ │ work.prg │ sponse is not │ │
│ │ │ received from │ │
│ │ │ server │ │
├───────────┼─────────────────────────────────┼───────────────┼───────┤
│ESS_RSM │ pra5.pra.pnc100.tpp240.6pppset‐ │ 40009 Re‐ │ 1,398 │
│ │ work.prg │ sponse is not │ │
│ │ │ received from │ │
│ │ │ server │ │
├───────────┼─────────────────────────────────┼───────────────┼───────┤
│ESS_RSM │ pra3.pra.pnc100.tpp240.6pppset‐ │ 40009 Re‐ │ 1,347 │
│ │ work.prg │ sponse is not │ │
│ │ │ received from │ │
│ │ │ server │ │
├───────────┼─────────────────────────────────┼───────────────┼───────┤
│ESS_RSM │ pra1.pra.pnc100.tpp240.6pppset‐ │ 40009 Re‐ │ 1,412 │
│ │ work.prg │ sponse is not │ │
│ │ │ received from │ │
│ │ │ server │ │
├───────────┼─────────────────────────────────┼───────────────┼───────┤
│ESS_RSM │ pra2.pra.pnc100.tpp240.6pppset‐ │ 40009 Re‐ │ 1,355 │
│ │ work.prg │ sponse is not │ │
│ │ │ received from │ │
│ │ │ server │ │
├───────────┼─────────────────────────────────┼───────────────┼───────┤
│ESS_RSM │ pra6.pra.pnc100.tpp240.6pppset‐ │ 40009 Re‐ │ 1,416 │
│ │ work.prg │ sponse is not │ │
│ │ │ received from │ │
│ │ │ server │ │
└───────────┴─────────────────────────────────┴───────────────┴───────┘
作为输出。有一些技巧可以使列(例如,第三列)更宽;让我知道你想知道什么。
警告:当您运行此命令时,tbl
将会 nroff
- 读取所有数据,
- 将其存储在内存和/或临时文件中,
- 计算列宽,然后
- 输出所有数据。
如果你有A 很多的数据,您可能会溢出临时存储的限制,并且命令将失败。您可以通过将输入分解为较小的文件来获得可用的结果。
警告:如果您的文件包含T{
或T}
、或 以句点 (.
) 或单引号 ('
),你可能会得到奇怪的结果。
答案2
awk '{$1=$1"|";$2=$2"|";$NF="|"$NF}1' input.txt | awk -F\| 'BEGIN{print "<table border=1>"}{gsub("\\|","</td><td>");print"<tr><td>"$0"</td></tr>"}END{print "</table>"}' > output.html
第一个 awk 用于通过 | 分隔值
第二个 awk 用于将值格式化为 HTML 表