如何将 cat 命令格式化为 bash 中的 table
How to format cat command as a table in bash
我有以下代码解析 XML 以显示文件中每个元素的节点值。
#Abbreviation - symbol
cat elements/*.xml | egrep "<symbol>.*</symbol>" |sed -e "s/<symbol>\(.*\)<\/symbol>//"|tr "|" " "
#Weight - atomic-weight
cat elements/*.xml | egrep "<atomic-weight>.*</atomic-weight>" |sed -e "s/<atomic-weight>\(.*\)<\/atomic-weight>//"|tr "|" " "
#Number atomic-number
cat elements/*.xml | egrep "<atomic-number>.*</atomic-number>" |sed -e "s/<atomic-number>\(.*\)<\/atomic-number>//"|tr "|" " " > number
如何将这三个输出格式化为 table 而不是一个巨大的顺序列表?
样本数据-
文件 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
试试这个:
#!/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>.*//")
number=$(grep -E "<atomic-number>.*</atomic-number>" "$F" | sed -e "s/.*<atomic-number>\(.*\)<\/atomic-number>.*//")
weight=$(grep -E "<atomic-weight>.*</atomic-weight>" "$F" | sed -e "s/.*<atomic-weight>\(.*\)<\/atomic-weight>.*//")
printf '%-9s %-9s %-9s\n' "$symbol" "$number" "$weight"
done
printf
允许您设置打印文本(或数字,或浮点数,...)的宽度和对齐方式的格式。
- 为了避免对权重值(例如小数位数)的任何解释,所有值都打印为字符串。
- for
printf
, '%-9s'
表示它将使用 9 个字符宽打印值,左对齐。如果没有 -
,它将右对齐。
printf
不输出回车 return 除非你告诉它,这解释了 \n
.
- 我重复使用了您的
grep ... | sed ...
命令,但有 2 个细节。 1 使用 grep -E
而不是 egrep
。 2 在 sed
的开头和结尾添加了 .*
以消除 <SOMETHING>
标签的前缀或后缀。
我得到的输出是:
$ ./so.bash
Symbol Number Weight
Ag 47 107.8682
Ba 56 137.327
如果您只知道它是有效的 XML,您最好使用 XML 解析器。例如,这样的解析器包含在 Ruby 或 Perl 中。这将使您还可以解析看起来像
的文件内容
<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
假设输入文件是 XML 外部通用解析实体,
如果包装在根元素中,则连接到 well-formed XML,
您可以使用 xmlstarlet 一次性处理它们:
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
:将文档元素包裹在 input 周围
--var ofs
: 定义输出字段分隔符
- 首先
--value-of
:发出header
- 列出每第 3 个元素(即符号),按符号排序为
A
递增 T
ext
- 改为按 atomic-number 排序:
--sort 'A:N:-' 'following-sibling::*[1]'
输出:
Symbol Number Weight
Ag 47 107.8682
Ba 56 137.327
我有以下代码解析 XML 以显示文件中每个元素的节点值。
#Abbreviation - symbol
cat elements/*.xml | egrep "<symbol>.*</symbol>" |sed -e "s/<symbol>\(.*\)<\/symbol>//"|tr "|" " "
#Weight - atomic-weight
cat elements/*.xml | egrep "<atomic-weight>.*</atomic-weight>" |sed -e "s/<atomic-weight>\(.*\)<\/atomic-weight>//"|tr "|" " "
#Number atomic-number
cat elements/*.xml | egrep "<atomic-number>.*</atomic-number>" |sed -e "s/<atomic-number>\(.*\)<\/atomic-number>//"|tr "|" " " > number
如何将这三个输出格式化为 table 而不是一个巨大的顺序列表?
样本数据-
文件 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
试试这个:
#!/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>.*//")
number=$(grep -E "<atomic-number>.*</atomic-number>" "$F" | sed -e "s/.*<atomic-number>\(.*\)<\/atomic-number>.*//")
weight=$(grep -E "<atomic-weight>.*</atomic-weight>" "$F" | sed -e "s/.*<atomic-weight>\(.*\)<\/atomic-weight>.*//")
printf '%-9s %-9s %-9s\n' "$symbol" "$number" "$weight"
done
printf
允许您设置打印文本(或数字,或浮点数,...)的宽度和对齐方式的格式。- 为了避免对权重值(例如小数位数)的任何解释,所有值都打印为字符串。
- for
printf
,'%-9s'
表示它将使用 9 个字符宽打印值,左对齐。如果没有-
,它将右对齐。 printf
不输出回车 return 除非你告诉它,这解释了\n
.- 我重复使用了您的
grep ... | sed ...
命令,但有 2 个细节。 1 使用grep -E
而不是egrep
。 2 在sed
的开头和结尾添加了.*
以消除<SOMETHING>
标签的前缀或后缀。
我得到的输出是:
$ ./so.bash
Symbol Number Weight
Ag 47 107.8682
Ba 56 137.327
如果您只知道它是有效的 XML,您最好使用 XML 解析器。例如,这样的解析器包含在 Ruby 或 Perl 中。这将使您还可以解析看起来像
的文件内容<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
假设输入文件是 XML 外部通用解析实体, 如果包装在根元素中,则连接到 well-formed XML, 您可以使用 xmlstarlet 一次性处理它们:
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
:将文档元素包裹在 input 周围
--var ofs
: 定义输出字段分隔符- 首先
--value-of
:发出header - 列出每第 3 个元素(即符号),按符号排序为
A
递增T
ext - 改为按 atomic-number 排序:
--sort 'A:N:-' 'following-sibling::*[1]'
输出:
Symbol Number Weight
Ag 47 107.8682
Ba 56 137.327