シェルコマンドの出力の文字数

シェルコマンドの出力の文字数

コマンドの出力の文字数を計算するスクリプトを書いています。一歩

たとえば、このコマンドを使用すると、そのコマンドの出力は 10 文字の長さであるため、readlink -f /etc/fstabが返されるはずです。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 シェル (sh) との互換性が望ましいです。

答え1

GNU 式:

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

GNU には、次の引数が、、...のような演算子であっても文字列として扱われるようにする特別な機能+があります。exprexprmatchlength+

上記は出力の末尾の改行を削除します。これを回避するには、次のようにします。

$ 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

POSIX: 正しい:

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

コマンド置換の前のスペースは、コマンドが で始まる文字列でクラッシュするのを防ぐ-ため、3 を減算する必要があります。

答え2

シェルの組み込み関数でこれをどうやって行うのかよく分からない(グヌークは) ですが、標準ツールが役立ちます:

  1. 文字数を数える whichを使うことができます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 つのステップで実行していたものと似ていますが、それらを 1 つの 1 行に組み合わせている点が異なります。

答え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

これらはすべてシェルの組み込み関数です (もちろん は含まれませんreadlink)。ただし、現在のシェルでそのように評価すると、len を取得する前に割り当てを行う必要があることが示唆されます。そのため、フォーマット文字列%.sの最初の引数を無効にして、の引数リストprintfの末尾のリテラル値に再度追加します。printf

eval

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

出力

10:/etc/fstab

同じことに近い結果を得ることができますが、最初のコマンドの変数の出力ではなく、stdout に出力されます。

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

...と書かれています...

10:/etc/fstab

...現在のシェル内のどの変数にも値を割り当てずに、ファイル記述子 1 に追加します。

関連情報