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

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

コマンド出力で文字数を計算する必要があるスクリプトを作成しています。ステップ

たとえば、このコマンドの出力長は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

フロント:

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

コマンド置換の前のスペースは、コマンドがそれで始まる文字列で衝突するのを防ぐため、-3を引く必要があります。

答え2

シェル組み込み機能を使用してこれを行う方法がわかりません(でもGnoucは)しかし、標準ツールが役に立つかもしれません。

  1. wc -mこれを使用して文字数を計算できます。残念ながら、最後の改行文字も計算されるため、最初に削除する必要があります。

    readlink -f /etc/fstab | tr -d '\n' | wc -m
    
  2. もちろん、あなたは使用することができますawk

    readlink -f /etc/fstab | awk '{print length($0)}'
    
  3. またはパール

    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つのライナーに組み合わせることを除いて、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

それが全てシェル内蔵機能です(もちろん除くreadlink)。ただし、現在のシェルでこれを評価することは、lenを取得する前に割り当てる必要があることを意味します。これが%.sフォーマット文字列の最初の引数を無視し、リストの末尾にargリテラル値をprintf追加した理由です。printf

そして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に。

関連情報