Text-Processing

使用可變和固定空間格式化命令輸出

  • April 23, 2016

我怎樣才能最好地保持左側的層次結構並對齊右側的大小值?

另外,同時我想將大小四捨五入到一位或兩位數。

我嘗試過printf但無法弄清楚如何保持這種格式。

$ port rdeps mtr 2>/dev/null | sed -E "1 s/.*of (.*) @.*/\1/" | while IFS= read -r line; do echo -e "$line" \\t\\t\\t\\t $(port space --units MiB --total $line 2>/dev/null | cut -d ' ' -f 1-2); done
mtr                  0.088 MiB
 pkgconfig                  0.615 MiB
   libiconv                 6.270 MiB
     gperf                  0.0 MiB
 glib2                  46.092 MiB
   xz               1.679 MiB
     gettext                24.825 MiB
       expat                1.109 MiB
       ncurses                  15.171 MiB
   libxml2                  10.405 MiB
     zlib               0.721 MiB
   libffi               0.141 MiB
   pcre                 5.954 MiB
     bzip2                  0.647 MiB
     libedit                0.795 MiB

這應該看起來像這樣

mtr                          0.08 MiB
 pkgconfig                  0.61 MiB
   libiconv                 6.27 MiB
     gperf                  0.00 MiB
 glib2                     46.09 MiB
   xz                       1.67 MiB
     gettext               24.82 MiB
       expat                1.10 MiB
       ncurses             15.17 MiB
   libxml2                 10.40 MiB
     zlib                   0.72 MiB
   libffi                   0.14 MiB
   pcre                     5.95 MiB
     bzip2                  0.64 MiB
     libedit                0.79 MiB

這裡有幾種方法:

帶四捨五入

正如您似乎意識到的那樣,printf它是用於格式化列印的絕佳工具。  %f是輸出“浮點數”的格式,即非整數的數字,即包含小數部分的數字。與所有 printf 格式一樣,緊隨其後的數字(整數!)% 指定格式化輸出的總長度,可能包括空格。此數字後面可以跟一個句點 ( .) 和另一個數字,該數字指定要顯示的小數位數(小數點右側的數字)。因此,例如,命令

printf "%12.2f\n" 1000000
printf "%12.2f\n" 1000
printf "%12.2f\n" 1
printf "%12.2f\n" 1.2345
printf "%12.2f\n" 1.6789
         ︙

將產生輸出

 1000000.00
    1000.00
       1.00
       1.23
       1.68
        ︙

請注意,1.6789四捨五入1.68.

所以你應該能夠用這個命令得到你想要的結果:

port rdeps mtr 2>/dev/null | sed -E "1 s/.*of (.*) @.*/\1/" |
    while IFS= read -r line
    do
        space="$(port space --units MiB --total $line 2>/dev/null | cut -d ' ' -f 1-2)"
        space_num=${space% *}
        space_mib=${space#* }
        printf "%-20s%12.2f %s\n" "$line" "$space_num" "$space_mib"
    done

space=$(…)命令只是port space我們一直在使用的命令替換,但結果(0.088 MiB例如,看起來像 )分配給臨時變數space. 然後space_num=${space% *}設置space_num為空格字元之前的部分(即數字;0.088在此範例中),並space_mib=${space#* }設置space_mib為空格字元之後的部分(即單位,MiB)。最後,我們將所有部分粘合在一起,printf %12.2f用於將數字顯示到小數點後兩位,四捨五入到最接近的百分之一,並在小數點上對齊(如前面的範例所示)。對於您的數據,這看起來像

mtr                         0.09 MiB
 pkgconfig                 0.62 MiB
   libiconv                6.27 MiB
     gperf                 0.00 MiB
 glib2                    46.09 MiB
   xz                      1.68 MiB
     gettext              24.83 MiB
       expat               1.11 MiB
       ncurses            15.17 MiB
   libxml2                10.40 MiB
     zlib                  0.72 MiB
   libffi                  0.14 MiB
   pcre                    5.95 MiB
     bzip2                 0.65 MiB
     libedit               0.80 MiB

請注意,0.088 MiB四捨五入到0.09 MiB

另請注意,space_mib它始終設置為MiB,因此我們實際上不需要計算它;

port rdeps mtr 2>/dev/null | sed -E "1 s/.*of (.*) @.*/\1/" |
    while IFS= read -r line
    do
        space_num="$(port space --units MiB --total $line 2>/dev/null | cut -d ' ' -f 1)"
        printf "%-20s%12.2f %s\n" "$line" "$space_num" "MiB"
    done

與上述相同。

帶截斷

要簡單地截斷數字,最好將它們視為字元串而不是數字。這個命令

port rdeps mtr 2>/dev/null | sed -E "1 s/.*of (.*) @.*/\1/" |
    while IFS= read -r line
    do
        printf "%-30s%s\n" "$line" \
                 "$(port space --units MiB --total $line 2>/dev/null | cut -d ' ' -f 1-2)"
    done | sed -E -e 's/(\..*) /\100 /' -e 's/(.{25}) *(....\...).*( .*)/\1\2\3/'

開始與我之前的答案幾乎相同。但隨後它通過 a 管道傳輸所有內容sed,它有兩個部分:

  • s/(\..*) /\100 /

這匹配小數點 ( \.) 和它之後的任意數量的字元 ( .*),最多但不包括空格字元。然後它將整個匹配字元串替換為空格 ( \1)、兩個零和一個空格之前的部分。(我本可以說s/(\..*)( )/\100\2/; 它會做同樣的事情。)這0.088 MiB變為0.08800 MiB0.0 MiB0.000 MiB如果您42. MiB的數據中有,它會將其更改為42.00 MiB. 但請注意,它假定每個數字都有一個小數點,即使它後面沒有任何數字。(它還假設字元串mtrpkgconfiglibiconv等中沒有句點)

我們需要這樣做以確保每個數字的小數點後至少有兩位數*;*gperf在我們進行此更正之前,情況並非如此。

  • s/(.{25}) *(....\...).*( .*)/\1\2\3/

.{25}.........................;的縮寫 即,25 個任意字元。我假設這足夠長以擷取最長(例如,libiconv),最深縮進的字元串。然後是任意數量的字元 ( .*),事實上,我希望它只是一堆空格。然後....\...匹配四個字元、一個小數點和另外兩個字元。如果您的空格數大於9999,則必須更改它以匹配小數點左側多於四位的數字。然後是任意數量的字元 ( .*),這將是小數點後前兩位之後的任意數字。然後是空格和行的其餘部分(( .*)),我希望是MiB. 然後它將這些片段重新組合為字元串(具有適當的前導和後續空格)、數字(具有足夠的前導空格以構成 中**.**的第五個字元\2),然後是單位。

此命令的輸出看起來像

mtr                         0.08 MiB
 pkgconfig                 0.61 MiB
   libiconv                6.27 MiB
     gperf                 0.00 MiB
 glib2                    46.09 MiB
   xz                      1.67 MiB
     gettext              24.82 MiB
       expat               1.10 MiB
       ncurses            15.17 MiB
   libxml2                10.40 MiB
     zlib                  0.72 MiB
   libffi                  0.14 MiB
   pcre                    5.95 MiB
     bzip2                 0.64 MiB
     libedit               0.79 MiB

請注意,0.088 MiB被截斷為0.08 MiB.

當然,如果您願意,您可以將上述任何復合命令全部放在一行中,並且您應該調整寬度常量(12202530等)以滿足您的需要。

引用自:https://unix.stackexchange.com/questions/272374