BASH输出列格式

时间:2014-09-30 22:04:25

标签: bash formatting

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

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

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

目前

#!/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"

以下列格式输出

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

但我希望格式化为整齐的对齐列以便于阅读

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

感谢大家的帮助!!

2 个答案:

答案 0 :(得分:7)

column非常好。但是,您已经在使用printf,它可以很好地控制输出格式。使用printf的功能还可以简化代码:

#!/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"

使用上面定义的格式,输出如下:

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

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

进一步改进

上面的代码用每个循环打开和关闭日志文件。正如Charles Duffy建议的那样,这可以避免,只需使用execstdout重定向到第一个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"

或者,正如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"

分组的一个优点是,在组之后,stdout会自动恢复到正常值。

答案 1 :(得分:3)

缩短了一点

#!/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

不需要每个printf重定向,但是您可以将脚本的一部分括在(...)中并在子shell中运行它,重定向它的输出。打印用一个选项卡分隔的每个字段,并使用column命令对其进行格式化。

无论如何,通常最好不要将文件名(也不是标题)放入脚本中并将其缩小为

#!/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

并使用它:

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

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

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