AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 788007
Accepted
Christopher Karsten
Christopher Karsten
Asked: 2024-12-12 18:47:23 +0800 CST2024-12-12 18:47:23 +0800 CST 2024-12-12 18:47:23 +0800 CST

将竖线分隔的列数据转换为电子邮件的 HTML 表格格式

  • 772

我正在尝试将分隔数据格式转换为 html 列表输出以用于电子邮件打印,但我不确定如何使用管道分隔符作为 HTML 表格格式的分隔符。

如果使用空格作为分隔符,则可以使用以下选项,但在此示例中,我使用的是管道符 (|)。

awk ' BEGIN {
print "To: '[email protected]'"
#print "MIME-Version: 1.0"
print "Content-Type: text/html"
print "Subject: This is a test email"
print "<html><body><table border=1 cellspacing=0 cellpadding=3>"
print "<tr>"
print "<td>SID</td>";
print "<td>PID</td>";
print "<td>Username</td>";
print "<td>Database</td>";
print "<td>Hostname</td>";
print "<td>Program</td>";
print "<td>Connected</td>";
print "<td>Idle Time</td>";
print "<td>Query Time</td>";
print "<td>EST COST</td>";
print "<td>SEQ SCAN</td>";
print "<td>Query</td>";
print "</tr>"
} {
print "<tr>"
print "<td>"$1"</td>";
print "<td>"$2"</td>";
print "<td>"$3"</td>";
print "<td>"$4"</td>";
print "<td>"$5"</td>";
print "<td>"$6"</td>";
print "<td>"$7"</td>";
print "<td>"$8"</td>";
print "<td>"$9"</td>";
print "<td>"$10"</td>";
print "<td>"$11"</td>";
print "<td>"$12"</td>";
print "</tr>"
} END {
print "</table></body></html>"
} ' /home/test/test.unl | sendmail -t

test.unl 文件内容如下:

15422216|-1|dwhvo|test|pd244zax.test.corp|N/A|    10:56:53|    -0:00:30|10:57:22|1045127|1|SELECT sba_sub_aux.sba_subscriber_id, sba_sub_aux.sba_id_number, sba_sub_aux.sba_matchcode, sba_sub_aux.sba_marketing, sba_su|

我希望通过电子邮件以表格形式实现以下内容。

在此处输入图片描述

awk
  • 4 4 个回答
  • 447 Views

4 个回答

  • Voted
  1. Stéphane Chazelas
    2024-12-12T19:56:20+08:002024-12-12T19:56:20+08:00

    如果删除尾随的|, 并添加标题:

    SID|PID|Username|Database|Hostname|Program|Connected|Idle Time|Query Time|EST COST|SEQ SCAN|Query
    

    然后,它就变成了一个以竖线为分隔符的简单 TSV,您可以使用它mlr来转换为适当的 CSV,然后pandoc可以将其转换为 HTML:

    {
      echo 'SID|PID|Username|Database|Hostname|Program|Connected|Idle Time|Query Time|EST COST|SEQ SCAN|Query'
      sed 's/|$//' your-file
    } |
      mlr --itsvlite --ifs pipe --ocsv cat |
      pandoc -s -f csv -t html -M 'pagetitle=My table' \
        -V 'header-includes=<style>table,th,td{border:1px solid;border-collapse:collapse}</style>' > result.html
    

    这将正确转义单元格内容中的 HTML。

    为了按照预期输出右对齐某些列,另一个选项是使用 markdown 作为中间格式。

    {
     echo 'SID|PID|Username|Database|Hostname|Program|Connected|Idle Time|Query Time|EST COST|SEQ SCAN|Query'
     sed 's/|$//' your-file
    } |
      mlr --itsvlite --ifs pipe --omd cat |
      perl -pe 's{-+}{substr("110000101110",$n++,1)?"$&:":":$&"}ge if $. == 2' |
      pandoc -s -f markdown -t html -M 'pagetitle=My table' \
        -V 'header-includes=<style>table,th,td{border:1px solid;border-collapse:collapse}</style>' > result.html
    

    上面使用“位图”perl来指定每列的对齐方式110000101110(1 为右,0 为左)。

    注意,mlr表格单元格中不会转义 Markdown 语法运算符。例如,如果您在某些单元格中有`foo`或,它们将被转换为HTML 等效项 ( , )。**bar**pandoc<code>foo</code><strong>bar</strong>

    如果pandoc在您的系统上安装很困难,您可以执行中的所有操作perl(应该是预先安装的),并且HTML::Table和HTML::Entities模块(如果尚未安装)应该很容易安装,即使您的系统没有打包(例如通过使用cpan):

    perl -MHTML::Table -MHTML::Entities -C -F'\|' -lane '
      BEGIN {
        $t = new HTML::Table(
          -border  => 1,
          -spacing => 0,
          -padding => 0,
          -head    => ["SID","PID","Username","Database","Hostname","Program","Connected","Idle Time","Query Time","EST COST","SEQ SCAN","Query"]
        );
      }
      $t->addRow(map {encode_entities$_} @F);
      END {
        $t->setColAlign(++$i, qw(left right)[$_]) for qw(1 1 0 0 0 0 1 0 1 1 1 0);
        print "<html><body>$t</body></html>";
      }' your-file > result.html
    

    Perl 还具有用于正确格式化和发送电子邮件的模块。

    • 7
  2. Best Answer
    Fravadona
    2024-12-12T20:00:39+08:002024-12-12T20:00:39+08:00

    正如@GillesQuénot 评论的那样,使用 awk 拆分一行|非常简单awk -F '|'。

    也就是说,我建议您定义两个函数:一个用于转义 HTML 文本(您显示的示例数据不需要它,但您永远不知道......),另一个用于打印整个 HTML 表行;这将使程序“更清洁”和更健壮。

    awk -F '|' '
        BEGIN {
            # ...
            print "<html><body><table border=1 cellspacing=0 cellpadding=3>"
            $0 = "SID|PID|Username|Database|Hostname|Program|Connected|Idle Time|Query Time|EST COST|SEQ SCAN|Query"
            print_as_tr()
        }
        {
            sub(/.$/, "") # fix the record for it to contain only what you want
            print_as_tr()
        }
        END {
            print "</table></body></html>"
        }
    
        function print_as_tr(    i) {
            print "<tr>"
            for (i = 1; i <= NF; i++)
                print "<td>" html_textify($i) "</td>"
            print "</tr>"
        }
        function html_textify(s) {
            gsub(/&/, "\\&amp;", s)
            gsub(/</, "\\&lt;", s)
            gsub(/>/, "\\&gt;", s)
            return s
        }
    '
    
    • 5
  3. Christopher Karsten
    2024-12-12T19:20:43+08:002024-12-12T19:20:43+08:00

    awk -F '|'对我有用。

    awk -F '|' ' BEGIN {
    print "To: '[email protected]'"
    #print "MIME-Version: 1.0"
    print "Content-Type: text/html"
    print "Subject: This is a test email"
    print "<html><body><table border=1 cellspacing=0 cellpadding=3>"
    print "<tr>"
    print "<td>SID</td>";
    print "<td>PID</td>";
    print "<td>Username</td>";
    print "<td>Database</td>";
    print "<td>Hostname</td>";
    print "<td>Program</td>";
    print "<td>Connected</td>";
    print "<td>Idle Time</td>";
    print "<td>Query Time</td>";
    print "<td>EST COST</td>";
    print "<td>SEQ SCAN</td>";
    print "<td>Query</td>";
    print "</tr>"
    } {
    print "<tr>"
    print "<td>"$1"</td>";
    print "<td>"$2"</td>";
    print "<td>"$3"</td>";
    print "<td>"$4"</td>";
    print "<td>"$5"</td>";
    print "<td>"$6"</td>";
    print "<td>"$7"</td>";
    print "<td>"$8"</td>";
    print "<td>"$9"</td>";
    print "<td>"$10"</td>";
    print "<td>"$11"</td>";
    print "<td>"$12"</td>";
    print "</tr>"
    } END {
    print "</table></body></html>"
    } ' /home/test/test.unl | sendmail -t
    

    输出按我想要的方式显示在电子邮件中。

    • 4
  4. Ed Morton
    2024-12-14T20:32:49+08:002024-12-14T20:32:49+08:00

    @Fravadona 的回答很好,这只是一种替代方法,使用任何 POSIX awk,在我看来,除了一些外观差异/花哨的东西之外,并没有明显更好。它主要只是通过为每个级别/ HTML 段提供单独的函数来隔离输出的每个特定部分,这可能会使它更容易一些,并且如果将来需要修改的话,不容易出错:

    $ cat tst.sh
    #!/usr/bin/env bash
    
    awk '
    
        BEGIN {
            FS = "[|]"
            Indent = -2
            prt_html()
            exit
        }
    
        function prt_html() {
            prt_beg("<html>")
            prt_body()
            prt_end("</html>")
        }
    
        function prt_body() {
            prt_beg("<body>")
            prt_table()
            prt_end("</body>")
        }
    
        function prt_table() {
            prt_beg("<table border=1 cellspacing=0 cellpadding=3>")
            numHdrCells = prt_hdr_row("SID|PID|Username|Database|Hostname|Program|Connected|Idle Time|Query Time|EST COST|SEQ SCAN|Query")
            prt_data_rows(numHdrCells)
            prt_end("</table>")
        }
    
        function prt_data_rows(numHdrCells, line) {
            while ( (getline line) > 0 ) {
                prt_data_row(numHdrCells,line)
            }
        }
    
        function prt_hdr_row(s,     numCells) {
            prt_beg("<tr>")
            numCells = prt_hdr_cells(s)
            prt_end("</tr>")
            return numCells
        }
    
        function prt_data_row(numHdrCells,s) {
            prt_beg("<tr>")
            prt_data_cells(numHdrCells,s)
            prt_end("</tr>")
        }
    
        function prt_hdr_cells(s,    numCells,f,i) {
            numCells = split(s, f)
            for (i = 1; i <= numCells; i++) {
                prt_cell("th",f[i])
            }
            return numCells
        }
    
        function prt_data_cells(numHdrCells,s,    f,i) {
            split(s, f)
            # Force the number of cells printed for each data row
            # to match the number of cells printed for the header.
            for (i = 1; i <= numHdrCells; i++) {
                prt_cell("td",f[i])
            }
        }
    
        function prt_cell(cellType,s) {
            Indent += 2
            # Strip any leading/trailing white space around this cell
            gsub(/^[[:space:]]+|[[:space:]]+$/, "", s)
            prt_indented("<" cellType ">" escape_html(s) "</" cellType ">")
            Indent -= 2
        }
    
        function escape_html(s) {
            gsub(/&/, "\\&amp;", s)
            gsub(/</, "\\&lt;", s)
            gsub(/>/, "\\&gt;", s)
            return s
        }
    
        function prt_beg(s) { Indent += 2; prt_indented(s) }
        function prt_end(s) { prt_indented(s); Indent -= 2 }
        function prt_indented(s) { printf("%*s%s\n", Indent, "", s) }
    
    ' "${@:--}"
    

    $ ./tst.sh test.unl
    <html>
      <body>
        <table border=1 cellspacing=0 cellpadding=3>
          <tr>
            <th>SID</th>
            <th>PID</th>
            <th>Username</th>
            <th>Database</th>
            <th>Hostname</th>
            <th>Program</th>
            <th>Connected</th>
            <th>Idle Time</th>
            <th>Query Time</th>
            <th>EST COST</th>
            <th>SEQ SCAN</th>
            <th>Query</th>
          </tr>
          <tr>
            <td>15422216</td>
            <td>-1</td>
            <td>dwhvo</td>
            <td>test</td>
            <td>pd244zax.test.corp</td>
            <td>N/A</td>
            <td>10:56:53</td>
            <td>-0:00:30</td>
            <td>10:57:22</td>
            <td>1045127</td>
            <td>1</td>
            <td>SELECT sba_sub_aux.sba_subscriber_id, sba_sub_aux.sba_id_number, sba_sub_aux.sba_matchcode, sba_sub_aux.sba_marketing, sba_su</td>
          </tr>
        </table>
      </body>
    </html>
    
    • 1

相关问题

  • 根据第一个逗号之前的匹配删除重复行数

  • 在另一个文件之后逐行追加行

  • 如何删除两行之间的单行

  • 重新排列字母并比较两个单词

  • 多行文件洗牌

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve