変数、文字列、または配列のサイズをバイト単位で取得するには?

変数、文字列、または配列のサイズをバイト単位で取得するには?

たとえば、配列を作成した場合:

$ array1=($(find /etc -mindepth 1 -maxdepth 1 -type d))
$ echo ${#array[@]}
105
$ for each in ${array1[@]}; do echo $each ; done
/etc/alternatives
/etc/apache2
/etc/apparmor
/etc/apparmor.d
... so on and so forth, you get the idea.

bashを使用して長さではなくバイト単位でサイズを印刷する方法はありますか?それとも文字数に基づいて手動で計算する必要がありますか?

私は次のことを試しました:

$ var2="a"
$ echo $var2 | wc -c
2
$ echo $var2
a

しかし、次はこうです。

$ var2=""
$ echo $var2 | wc -c
1
$ echo $var2

空白変数の存在は1バイトのようです。しかし、1文字の文字数は2文字です。

$ echo a | wc -c
2
$ echo a | wc -m
2
$ echo aa | wc -c
3
$ echo aa | wc -m
3

改行文字は1バイトで、各文字も1バイトであるように見えます。配列を取得し、新しい行数を数え、文字数を数え、計算をするのは難しいようです。私はとても考えているのですか?それとも正確な数値を知らせるユーティリティがありますか?

ベストアンサー1

array1=($(find /etc -mindepth 1 -maxdepth 1 -type d))

findこれは、リストを取得するために出力に対して分割+グローブを実行するため、間違っています(とにかくfindない出力は-print0後処理できません)。 (4.4+) の正しい構文はbash次のとおりです。

readarray -td '' array1 < <(find /etc -mindepth 1 -maxdepth 1 -type d -print0)

またはzsh:

array1=(/etc/*(ND/))

存在するecho $var | wc -c

出力からバイトを計算していますecho$varこれはいくつかの理由でバイト数ではありません。

  • 引用するのを忘れた$varので分割+グローブの影響を受けます。
  • echo移行を試してください。いくつかの実装は\xエスケープシーケンスを拡張し、いくつかは値を-nオプションとして扱います。
  • 最後に、echo改行文字が出力に追加されます(-n一部の実装ではスキップできますecho)。

ここでwcバイト数を計算するには、次のようにします。

printf %s "$var" | wc -c

では次に展開しますbash${#var}数値変数から。バイト数にするには、ロケールをCに変更するだけです。

LC_ALL=C
echo "${#var}"

配列内のすべての要素のバイト長の合計を取得するには、要素を連結して結果文字列の長さを取得します。

printf %s "${array[@]}" | wc -c

または:

IFS=
concat="${array[*]}"
LC_ALL=C
echo "${#concat}"

zshを使用すると、次のことができます。

() { set -o localoptions +o multibyte
  echo ${#${(j[])array}}
}

ここで、パラメータ拡張フラグは、グローバルを使用するのではなく、配列内の要素を連結するj[sep]ために使用されます。ロケールを変更する代わりに、getオプションを無効にすることができます。"${array[*]}"$IFSCmultibyte特徴バイト(これはローカル匿名関数で行われます)。

バイトと文字の違いを確認するには、マルチバイトエンコーディングを文字マップ(UTF-8、GB18030、BIG5など)として使用し、マルチバイトエンコーディング文字に使用するロケールが必要です。a通常は1バイトにエンコードされているため、違いは見られません。たとえば、エンコーディングはUTF-8では3バイト、ISO8859-15では1バイトです。

はい( zsh):

$ a=($'\xe2\x82\xac20' '$25' $'\xa420')
$ locale charmap
UTF-8
$ typeset -p a
typeset -a a=( €20 '$25' $'\M-$20' )
$ printf %s "${a[@]}" | wc -c
11
$ printf %s "${a[@]}" | wc -m
8
$ echo ${#${(j[])a}}
9
$ (){set -o localoptions +o multibyte; echo ${#${(j[])a}}}
11

文字マップがISO8859-15のロケールに切り替える場合:

$ locale charmap
ISO-8859-15
$ a=($'\xe2\x82\xac20' '$25' $'\xa420')
$ typeset -p a
typeset -a a=( â¬20 '$25' €20 )
$ printf %s "${a[@]}" | wc -c
11                           
$ printf %s "${a[@]}" | wc -m
11
$ echo ${#${(j[])a}}
11
$ (){set -o localoptions +o multibyte; echo ${#${(j[])a}}}
11

ISO8859-15はシングルバイト文字エンコーディングなので特徴バイトそこに。

追加資料:


bash(またはzsh)に似ていますwc -mが、bash(またはzsh)も文字としてデコードできないバイトをそれぞれ1文字として計算します。

おすすめ記事