【问题标题】:How to format cat command as a table in bash如何在 bash 中将 cat 命令格式化为表格
【发布时间】:2021-12-21 00:22:15
【问题描述】:

我有以下代码解析 XML 以显示文件中每个元素的节点值。

#Abbreviation - symbol
cat elements/*.xml |  egrep "<symbol>.*</symbol>" |sed -e "s/<symbol>\(.*\)<\/symbol>/\1/"|tr "|" " "

#Weight - atomic-weight
cat elements/*.xml |  egrep "<atomic-weight>.*</atomic-weight>" |sed -e "s/<atomic-weight>\(.*\)<\/atomic-weight>/\1/"|tr "|" " "

#Number atomic-number
cat elements/*.xml |  egrep "<atomic-number>.*</atomic-number>" |sed -e "s/<atomic-number>\(.*\)<\/atomic-number>/\1/"|tr "|" " " > number

如何将这三个输出格式化为一个表格而不是一个巨大的顺序列表?

样本数据 -

文件1 -

  <symbol>Ag</symbol>
  <atomic-number>47</atomic-number>
  <atomic-weight>107.8682</atomic-weight>

文件2-

  <symbol>Ba</symbol>
  <atomic-number>56</atomic-number>
  <atomic-weight>137.327</atomic-weight>

期望的输出 -

Symbol   Number   Weight
Ag       47       107.8682
Ba       56       137.327

【问题讨论】:

  • 我的错,我添加了示例数据和所需的输出
  • 那是一个宏伟的useless (e)grep; tr 也可以轻松折叠到 sed 脚本中。
  • 很好,像这样的 cmets 是保持堆栈溢出精英的原因。感谢您的意见...

标签: bash sed


【解决方案1】:

试试这个:

#!/bin/bash

printf '%-9s %-9s %-9s\n' "Symbol" "Number" "Weight"

for F in *.xml
do
    symbol=$(grep -E "<symbol>.*</symbol>" "$F"               | sed -e "s/.*<symbol>\(.*\)<\/symbol>.*/\1/")
    number=$(grep -E "<atomic-number>.*</atomic-number>" "$F" | sed -e "s/.*<atomic-number>\(.*\)<\/atomic-number>.*/\1/")
    weight=$(grep -E "<atomic-weight>.*</atomic-weight>" "$F" | sed -e "s/.*<atomic-weight>\(.*\)<\/atomic-weight>.*/\1/")

    printf '%-9s %-9s %-9s\n' "$symbol" "$number" "$weight"
done
  • printf 允许您设置打印文本(或数字,或浮点数,...)的宽度和对齐方式。
  • 为避免对重量值进行任何解释(例如,小数位数),所有值都打印为字符串。
  • 对于printf'%-9s' 表示它将使用 9 个字符宽打印值,左对齐。如果没有-,它将右对齐。
  • printf 不会输出回车,除非您告诉它,这解释了 \n
  • 我重用了您的grep ... | sed ... 命令,但有两个细节。 1 使用grep -E 而不是egrep2sed 的开头和结尾添加了.*,以消除&lt;SOMETHING&gt; 标签的前缀或后缀。

我得到的输出是:

$ ./so.bash 
Symbol    Number    Weight   
Ag        47        107.8682 
Ba        56        137.327  

【讨论】:

    【解决方案2】:

    如果您唯一知道的是有效的 XML,那么您最好使用 XML 解析器。例如,RubyPerl 都包含此类解析器。这将允许您还解析看起来像的文件内容

    <atomic-weight>
      107.8682
    </atomic-weight>
    

    但是,如果您可以确保输入文件完全遵循您发布的格式,您可以执行以下操作:

    for file in File1 File2
    do
      tr '<>' ' ' <$file | cut -d ' ' -f 3
    done
    

    如果您需要将数据格式化为特定位置的列,您可以执行类似的操作

    for file in File1 File2
    do
      printf ' put your format specification here ' $(tr '<>' ' ' <$file | cut -d ' ' -f 3)
    done
    

    【讨论】:

      【解决方案3】:

      如果输入文件是 XML 外部通用解析实体, 如果包装在根元素中,则连接到格式良好的 XML, 您可以使用 一次性处理它们:

      printf '<doc>%s</doc>\n' "$(cat file*.xml)" |
      xmlstarlet select --template --var ofs="'$(printf "\t")'" \
          --value-of 'concat("Symbol", $ofs, "Number", $ofs, "Weight")' --nl \
          --match '*/*[position() mod 3 = 1]' --sort 'A:T:-' '.' \
          --value-of 'concat(., $ofs, following-sibling::*[1], $ofs, following-sibling::*[2])' --nl
      
      • printf:在输入周围包裹一个文档元素
      • --var ofs : 定义输出字段分隔符
      • 第一个--value-of:发出标头
      • 列出按符号排序的每个第三个元素(即符号) Ascending Text
      • 改为按原子序数排序:--sort 'A:N:-' 'following-sibling::*[1]'

      输出:

      Symbol  Number  Weight
      Ag      47      107.8682
      Ba      56      137.327
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-02-22
        • 2011-09-21
        • 1970-01-01
        • 2021-08-25
        • 1970-01-01
        • 1970-01-01
        • 2014-05-20
        • 1970-01-01
        相关资源
        最近更新 更多