使用可變和固定空間格式化命令輸出
我怎樣才能最好地保持左側的層次結構並對齊右側的大小值?
另外,同時我想將大小四捨五入到一位或兩位數。
我嘗試過
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 MiB
和0.0 MiB
。0.000 MiB
如果您42. MiB
的數據中有,它會將其更改為42.00 MiB
. 但請注意,它假定每個數字都有一個小數點,即使它後面沒有任何數字。(它還假設字元串mtr
、pkgconfig
、libiconv
等中沒有句點)我們需要這樣做以確保每個數字的小數點後至少有兩位數*;*
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
.當然,如果您願意,您可以將上述任何復合命令全部放在一行中,並且您應該調整寬度常量(
12
、20
、25
、30
等)以滿足您的需要。