BASH 输出列格式

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26130909/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 11:27:06  来源:igfitidea点击:

BASH output column formatting

bashformatting

提问by aLee788

First time posting. HELLO WORLD. Working on my first script that just simply checks if a list of my websites are online and then returns the HTTP code and the amount of time it took to return that to another file on my desktop.

第一次发帖。你好,世界。处理我的第一个脚本,它只是简单地检查我的网站列表是否在线,然后返回 HTTP 代码以及将其返回到桌面上另一个文件所需的时间。

-- THIS SCRIPT WILL BE RUNNING ON MAC OSX --

-- 此脚本将在 MAC OSX 上运行 --

I would like to amend my script so that it formats its output into 3 neat columns.

我想修改我的脚本,以便将其输出格式化为 3 个整齐的列。

currently

目前

#!/bin/bash
file="/Users/USER12/Desktop/url-list.txt"
printf "" > /Users/USER12/Desktop/url-results.txt
while read line
do
    printf "$line" >> /Users/USER12/Desktop/url-results.txt
    printf "\t\t\t\t" >> /Users/USER12/Desktop/url-results.txt
    curl -o /dev/null --silent --head --write-out '%{http_code} %{time_total}' "$line" >> /Users/USER12/Desktop/url-results.txt
    printf "\n" >> /Users/USER12/Desktop/url-results.txt
done <"$file"

which outputs in the following format

它以以下格式输出

google.com              200 0.389
facebook.com                200 0.511
abnormallyLongDomain.com                200 0.786

but i would like to format into neat aligned columns for easy reading

但我想格式化成整齐对齐的列以便于阅读

DOMAIN_NAME                 HTTP_CODE   RESPONSE_TIME
google.com                  200         0.389
facebook.com                200         0.511
abnormallyLongDomain.com    200         0.486

Thanks for the help everyone!!

谢谢大家的帮助!!

回答by John1024

columnis very nice. You are, however, already using printfwhich gives you fine control over the output format. Using printf's features also allows the code to be somewhat simplified:

column是非常好的。但是,您已经在使用printf它,可以很好地控制输出格式。Usingprintf的特性还允许代码稍微简化:

#!/bin/bash
file="/Users/USER12/Desktop/url-list.txt"
log="/Users/USER12/Desktop/url-results.txt"
fmt="%-25s%-12s%-12s\n"
printf "$fmt" DOMAIN_NAME HTTP_CODE RESPONSE_TIME > "$log"
while read line
do
    read code time < <(curl -o /dev/null --silent --head --write-out '%{http_code} %{time_total}' "$line")
    printf "$fmt" "$line" "$code" "$time" >> "$log"
done <"$file"

With the above defined format, the output looks like:

使用上面定义的格式,输出看起来像:

DOMAIN_NAME              HTTP_CODE   RESPONSE_TIME
google.com               301         0.305
facebook.com             301         0.415
abnormallyLongDomain.com 000         0.000

You can fine-tune the output format, such as spacing or alignment, by changing the fmtvariable in the script.

您可以通过更改fmt脚本中的变量来微调输出格式,例如间距或对齐方式。

Further Refinements

进一步改进

The above code opens and closes the log file with each loop. This can be avoided as Charles Duffy suggests, simply by using execto redirect stdoutto the log file before the first printfstatement:

上面的代码在每个循环中打开和关闭日志文件。正如查尔斯·达菲 (Charles Duffy) 所建议的,这可以避免,只需在第一条语句之前使用exec重定向stdout到日志文件即可printf

#!/bin/bash
file="/Users/USER12/Desktop/url-list.txt"
exec >"/Users/USER12/Desktop/url-results.txt"
fmt="%-25s%-12s%-12s\n"
printf "$fmt" DOMAIN_NAME HTTP_CODE RESPONSE_TIME
while read line
do
    read code time < <(curl -o /dev/null --silent --head --write-out '%{http_code} %{time_total}' "$line")
    printf "$fmt" "$line" "$code" "$time"
done <"$file"

Alternatively, as Chepner suggests, the print statements can be grouped:

或者,正如 Chepner 建议的那样,打印语句可以分组:

#!/bin/bash
file="/Users/USER12/Desktop/url-list.txt"
fmt="%-25s%-12s%-12s\n"
{
printf "$fmt" DOMAIN_NAME HTTP_CODE RESPONSE_TIME
while read line
do
    read code time < <(curl -o /dev/null --silent --head --write-out '%{http_code} %{time_total}' "$line")
    printf "$fmt" "$line" "$code" "$time"
done <"$file"
} >"/Users/USER12/Desktop/url-results.txt"

An advantage of grouping is that, after the group, stdout is automatically restored to its normal value.

分组的一个好处是,分组后,stdout 会自动恢复到正常值。

回答by jm666

Shortened a bit

缩短了一点

#!/bin/bash

file="./url.txt"
fmt="%s\t%s\t%s\n"
( printf "$fmt" "DOMAIN_NAME" "HTTP_CODE" "RESPONSE_TIME"
while read -r line
do
    printf "$fmt" "$line" $(curl -o /dev/null --silent --head --write-out '%{http_code} %{time_total}' "$line")
done <"$file" ) | column -t > ./out.txt

Don't need redirect every printfbut you can enclose the part of your script into (...)and run it in an subshell a redirect it's output. Print every field separated with one tab and use the columncommand to format it nicely.

不需要每次都重定向,printf但您可以将脚本的一部分包含在其中(...)并在子shell 中运行它作为重定向它的输出。打印用一个制表符分隔的每个字段,并使用该column命令很好地对其进行格式化。

Anyway, usually is better don't put filenames (nor headers) into the script and reduce it to

无论如何,通常最好不要将文件名(或标题)放入脚本并将其减少到

#!/bin/bash

while read -r line
do
    printf "%s\t%s\t%s\n" "$line" $(curl -o /dev/null --silent --head --write-out '%{http_code} %{time_total}' "$line")
done | column -t

and use it like:

并像这样使用它:

myscript.sh < url-list.txt >result.txt

this allows you use your script in pipes, like:

这允许您在管道中使用脚本,例如:

something_produces_urls | myscript.sh | grep 200 > somewhere.txt