Linux

我可以對列製表符大小進行格式化,以使間距在 Linux 中達到最低公分母嗎?

  • November 1, 2021

我可以stat用來創建一個 ls 輸出,顯示兩種格式的權限資訊,這很方便:

stat --printf="%A\t%a\t%h\t%U\t%G\t%s\t%.19y\t%n\n" . .*

drwxr-xr-x      755     4       boss    boss    4096    2021-10-29 22:49:12     .
drwxr-xr-x      755     4       boss    boss    4096    2021-10-29 22:49:12     .
drwxr-xr-x      755     36      boss    boss    4096    2021-11-01 11:30:24     ..
-rw-r--r--      644     1       boss    boss    97708   2021-11-01 11:30:16     .custom
-rw-r--r--      644     1       boss    boss    4013    2021-10-11 22:04:04     .custom-dk

然而,列之間的間距使用\t這很好,但相當“間隙”。這讓我很好奇,是否有一種通用方法來對這樣的任何輸出進行後處理,以使列處於一個空格間隙的最低公分母,即是否有一種通用方法可以將上面的內容調整為類似於下面的內容使用awkorsed或類似的(如果可能的話,我也將數字列正確地證明為“理想”輸出)?

drwxr-xr-x 755  4 boss boss  4096 2021-10-29 22:49:12 .
drwxr-xr-x 755  4 boss boss  4096 2021-10-29 22:49:12 .
drwxr-xr-x 755 36 boss boss  4096 2021-11-01 11:30:24 ..
-rw-r--r-- 644  1 boss boss 97708 2021-11-01 11:30:16 .custom
-rw-r--r-- 644  1 boss boss  4013 2021-10-11 22:04:04 .custom-dk

關於您問題中的“或 sed” - sed 是用於對單個字元串進行簡單 s/old/new/ 轉換的正確工具,您所做的不是那樣的,因此 sed 甚至不應該是一個選項考慮。

使用 2-pass 方法,首先確定每列的最大寬度和對齊方式,然後在列印時使用它們,在每個 Unix 機器上的任何 shell 中使用任何 awk:

$ cat tst.awk
BEGIN { FS="\t" }
NR==FNR {
   for (i=1; i<=NF; i++) {
       align[i] = ( $i ~ /^[0-9]+$/ ? "" : "-" )
       width[i] = ( length($i) > width[i] ? length($i) : width[i] )
   }
   next
}
{
   for (i=1; i<NF; i++) {
       printf "%" align[i] width[i] "s ", $i
   }
   print $NF
}
$ awk -f tst.awk file file
drwxr-xr-x 755  4 boss boss  4096 2021-10-29 22:49:12 .
drwxr-xr-x 755  4 boss boss  4096 2021-10-29 22:49:12 .
drwxr-xr-x 755 36 boss boss  4096 2021-11-01 11:30:24 ..
-rw-r--r-- 644  1 boss boss 97708 2021-11-01 11:30:16 .custom
-rw-r--r-- 644  1 boss boss  4013 2021-10-11 22:04:04 .custom-dk

以上假設您的最後一列始終是左對齊的,如果不是這種情況,請告訴我們,因為這兩種方式都不難處理。它還假設列的對齊方式可以由輸入最後一行中的欄位中的值(數字或非數字)確定。

如果輸入必須來自管道而不是文件(因此您不能兩次打開輸入),那麼您可以將輸入儲存在數組中並在 END 部分中列印:

$ cat tst.awk
BEGIN { FS = "\t" }
{
   for (i=1; i<=NF; i++) {
       width[i] = ( length($i) > width[i] ? length($i) : width[i] )
       align[i] = ( $i ~ /^[0-9]+$/ ? "" : "-" )
       vals[NR,i] = $i
   }
}
END {
   for (n=1; n<=NR; n++) {
       for (i=1; i<NF; i++) {
           printf "%" align[i] width[i] "s ", vals[n,i]
       }
       print vals[n,NF]
   }
}

然後將其稱為:

$ stat --printf="%A\t%a\t%h\t%U\t%G\t%s\t%.19y\t%n\n" . .* | awk -f tst.awk

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