shell 指令輸出中的字元數

shell 指令輸出中的字元數

我正在編寫一個腳本,需要計算命令輸出中的字元數一步

例如,使用該命令readlink -f /etc/fstab應該返回,10因為該命令的輸出有 10 個字元長。

使用以下程式碼可以透過儲存變數實現這一點:

variable="somestring";
echo ${#variable};
# 10

不幸的是,對命令產生的字串使用相同的公式不起作用:

${#(readlink -f /etc/fstab)};
# bash: ${#(readlink -f /etc/fstab)}: bad substitution

我知道可以透過先將輸出儲存到變數來做到這一點:

variable=$(readlink -f /etc/fstab);
echo ${#variable};

但我想刪除額外的步驟。

這可能嗎?最好僅使用內建或標準實用程式與 Almquist shell (sh) 相容。

答案1

GNU 表達式:

$ expr length + "$(readlink -f /etc/fstab)"
10

GNU+有一個特殊功能,expr可以確保下一個參數被視為字串,即使它碰巧是exprmatch, length, +...這樣的運算符。

上面的程式碼將去除輸出中任何尾隨的換行符。要解決這個問題:

$ expr length + "$(readlink -f /etc/fstab; printf .)" - 2
10

結果被減去2因為最後的換行符和我們添加的readlink字元。.

對於 Unicode 字串,expr似乎不起作用,因為它返回字串的長度(以位元組為單位)而不是字元數(請參閱654線

$ LC_ALL=C.UTF-8 expr length ăaa
4

所以,你可以使用:

$ printf "ăaa" | LC_ALL=C.UTF-8 wc -m
3

正面:

$ expr " $(readlink -f /etc/fstab; printf .)" : ".*" - 3
10

命令替換之前的空格可以防止命令以 開頭的字串崩潰-,所以我們需要減去 3。

答案2

不知道如何使用 shell 內建函數來做到這一點(雖然 Gnouc 是)但標準工具可以幫助:

  1. 您可以使用wc -m它來計算字元數。不幸的是,它也計算最後的換行符,所以你必須先刪除它:

    readlink -f /etc/fstab | tr -d '\n' | wc -m
    
  2. 當然可以使用awk

    readlink -f /etc/fstab | awk '{print length($0)}'
    
  3. 或 Perl

    readlink -f /etc/fstab | perl -lne 'print length'
    

答案3

我通常會這樣做:

$ echo -n "$variable" | wc -m
10

為了執行命令,我會像這樣調整它:

$ echo -n "$(readlink -f /etc/fstab)" | wc -m
10

這種方法與您在 2 個步驟中所做的類似,只是我們將它們組合成一個襯裡。

答案4

這可以工作,dash但它確實要求目標變數絕對為空或未設定。這就是為什麼這實際上是命令 - 我$l在第一個命令中明確清空:

l=;printf '%.slen is %d and result is %s\n' \
    "${l:=$(readlink -f /etc/fstab)}" "${#l}" "$l"

輸出

len is 10 and result is /etc/fstab

這就是所有 shell 內建函數 - 當然不包括readlink- 但在當前 shell 中對其進行評估意味著您必須在獲取 len 之前進行賦值,這就是為什麼我%.s忽略格式字串中的第一個參數printf並再次添加它printfarg列表尾部的文字值。

eval

l=$(readlink -f /etc/fstab) eval 'l=${#l}:$l'
printf %s\\n "$l"

輸出

10:/etc/fstab

您可以接近相同的事情,但是您可以在標準輸出上獲取它,而不是第一個命令中變數的輸出:

PS4='${#0}:$0' dash -cx '2>&1' "$(readlink -f /etc/fstab)"

....其中寫...

10:/etc/fstab

....到檔案描述符 1,而不為目前 shell 中的任何變數分配任何值。

相關內容