如何获取变量、字符串或数组的大小(以字节为单位)?

如何获取变量、字符串或数组的大小(以字节为单位)?

例如,如果我构建一个数组:

$ 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

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

这是错误的,因为它对 的输出执行 split+glob 来find获取列表(并且findwithout的输出-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所以它受到 split+glob 的影响
  • 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]参数扩展标志用于连接数组的元素,而不是使用"${array[*]}"which 使用全局$IFS.C我们可以禁用该multibyte选项来获取,而不是修复区域设置特点字节(我们在本地匿名函数中执行此操作)。

请注意,要查看字节和字符之间的差异,您需要一种使用多字节编码作为其字符映射(例如 UTF-8、GB18030、BIG5...)的语言环境以及在多个字节上编码的字符。a通常以一个字节进行编码,因此您不会看到差异。例如,在 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)也会将无法解码为字符的字节分别计算为一个字符。

相关内容