您可以调用外部实用程序(请参阅其他答案),但是它们会使脚本变慢,并且很难正确设置管道。
sh
在zsh中,您可以编写${#$(readlink -f /etc/fstab)}
以获取命令替换的长度。注意,这不是命令输出的长度,而是没有尾随换行符的输出长度。
如果需要输出的确切长度,请在末尾输出一个额外的非换行符,然后减去一个。
$((${#$(readlink -f /etc/fstab; echo .)} - 1))
如果您想要的是命令输出中的有效负载,那么您需要在此处减去两个,因为的输出readlink -f
是规范路径和换行符。
$((${#$(readlink -f /etc/fstab; echo .)} - 2))
这与${#$(readlink -f /etc/fstab)}
标准路径本身以换行符结尾的罕见但可能的情况不同。
对于此特定示例,您根本不需要外部实用程序,因为zsh具有一个内置的结构,该结构等效于readlink -f
history修饰符A
。
echo /etc/fstab(:A)
要获取长度,请在参数扩展中使用history修饰符:
${#${:-/etc/fstab}:A}
如果文件名包含在变量中filename
,则为${#filename:A}
。
Bourne / POSIX风格的壳
我所知道的纯Bourne / POSIX外壳(Bourne,ash,mksh,ksh93,bash,yash…)都没有类似的扩展名。如果需要将参数替换应用于命令替换的输出或嵌套参数替换,请使用连续的阶段。
您可以根据需要将处理填充到一个函数中。
command_output_length_sans_trailing_newlines () {
set -- "$("$@")"
echo "${#1}"
}
要么
command_output_length () {
set -- "$("$@"; echo .)"
echo "$((${#1} - 1))"
}
但是通常没有好处;除了ksh93之外,这会导致额外的fork能够使用该函数的输出,因此使您的脚本变慢,并且几乎没有可读性。
再次,输出readlink -f
是规范路径和换行符;如果您需要规范路径的长度,请减去2而不是中的1 command_output_length
。command_output_length_sans_trailing_newlines
仅当规范路径本身未以换行符结尾时,使用才能给出正确的结果。
字节与字符
${#…}
应该是字符长度,而不是字节长度,这会导致多字节语言环境有所不同。ksh93,bash和zsh的最新版本合理地根据扩展构造LC_CTYPE
时的value计算以字符为单位的长度${#…}
。许多其他常见的shell并不真正支持多字节语言环境:从破折号0.5.7,mksh 46和posh 0.12.3开始,${#…}
返回以字节为单位的长度。如果您希望以可靠的方式输入字符长度,请使用该wc
实用程序:
$(readlink -f /etc/fstab | wc -m)
只要$LC_CTYPE
指定有效的语言环境,您就可以确信这会出错(在不支持多字节语言环境的古老或受限平台上)或返回正确的字符长度。(对于Unicode,“字符长度”表示代码点的数量-由于合并字符等复杂性,字形的数量又是另一回事了。)
如果要以字节为单位的长度,请LC_CTYPE=C
临时设置,或使用wc -c
代替wc -m
。
使用来计数字节或字符wc
包括命令中的任何尾随换行符。如果要以字节为单位的规范路径的长度,则为
$(($(readlink -f /etc/fstab | wc -c) - 1))
要以字符为单位,请减去2。
readlink -f /etc/fstab
为11个字符。不要忘记换行符。否则,您将/etc/fstabluser@cern:~$
在从外壳运行时看到它。