在 bash 中,假设某个函数生成一个未知长度的简单数组。该数组将被转换并打印在屏幕上:每行旁边都有一个小索引号,以便从中进行选择。空间有限,演示必须完美无缺,工具集是……嗯,没有多余的装饰,我想说。
我怎样才能找到字符串长度的索引号本身(出于格式化目的)这不是数组上的值。例如,如果数组有 334,345 个项目(您将使用 打印最后一个项目echo ${hugearray[334344]}
),那么这6
就是我要查找的内容。
ncurses
我必须留在 bash 中,因为目标系统中没有 tput 或其他“花哨”的格式化实用程序。只打击本身。
${#WORD[@]}
给了我项目的总数,从中我构建了一些基本的构造来获得它:
$〉pkglist+=($(brew list -1)) # ← I'm testing on a Mac.
$〉printf "%s\n" ${pkglist[@]}
automake
…
xquartz
$〉echo ${#pkglist[@]}
68
$〉indexlength=${#pkglist[@]}
$〉echo ${#indexlength}
2
它可以工作,但并不完全优雅。为我辩护,我不是开发者但我有点希望已经有更好、更简单的方法来做到这一点,嵌套间接或其他一些 bash 巫毒。但是常规的东西对实际数据的作用已经足够令人困惑了,我认为最好在后悔之前先问一下(目标系统只有根帐户)。有没有?
谢谢!
答案1
如果您使用的是 Macos,则应该可以访问 zsh,因此不必使用 bash。
在 zsh 中,数组长度就像$#array
在 csh 中一样,您可以嵌套参数扩展运算符,因此您可以执行${#${#array}}
1 来获取数组长度的十进制表示形式的长度。
$ a=(qwe asdasd qewqw)
$ () {printf "%${#${#a}}d %s\n" "${@:^a}"} {1..$#a}
1 qwe
2 asdasd
3 qweqe
$ a=( {a..m} )
$ () {printf "%${#${#a}}d %s\n" "${@:^a}}" {1..$#a}
1 a
2 b
3 c
4 d
5 e
6 f
7 g
8 h
9 i
10 j
11 k
12 l
13 m
请注意,所有array=(...)
, array+=(...)
,{x..y}
均已由 bash 从 zsh 复制(通常通过 ksh 间接复制)。{1..$expansion}
在 zsh 或 ksh 中有效,但在 bash 中无效。
数组${a:^b}
压缩运算符和() {code} args
匿名函数仍然是 zsh 特有的。
如果您必须使用 bash,那么像您这样分两步进行可能就最好了。
您可以在一次扩展中完成此操作$(((l=${#array[@]}),SHLVL[l=\${#l}],l))
,依赖于数组索引的延迟评估,但这对易读性没有帮助,并且可能无法面向未来。
另请注意,在 bash 中(就像在 ksh 中,不幸的是,bash 的数组设计被复制了),数组并不是真正的数组,而是更像关联数组,键为正整数并从 0 开始(与大多数其他 shell 不同,1)
bash-5.1$ a=( [5]=123 [123]=qwe [4567]=asd )
bash-5.1$ typeset -p a
declare -a a=([5]="123" [123]="qwe" [4567]="asd")
bash-5.1$ echo "${#a[@]}"
3
3
是数组中元素的数量,但不是您需要的最高键值:
bash-5.1$ keys=("${!a[@]}")
bash-5.1$ echo "${keys[@]: -1}"
4567
因此,如果您想打印对齐的键和值,您需要类似的东西
printarray() {
local -n arr="$1"
local -a keys=("${!arr[@]}")
local highest_key="${keys[@]: -1}"
local key_width="${#highest_key}"
local key
for key in "${keys[@]}"; do
printf '%*d %s\n' "$key_width" "$key" "${arr[key]}"
done
}
bash-5.1$ printarray a
5 123
123 qwe
4567 asd
(不适用于 Macos 上的古老 bash;local -n
需要 bash 4.3 或更高版本)
¹${#$#array}
不起作用,因为它被视为,即使用Korn 风格运算符从其开头剥离后${#${$#array}}
的长度。$$
array
${var#pattern}
答案2
正如您所说,这会是某种 BASH 巫术吗? - 没有额外的变量
: $((${#pkglist[*]}-1)); echo ${#_};
,但 $_ 可能会导致调试问题 - 长脚本
答案3
编辑:我道歉;正如 @ilkkachu 善意提醒我的那样,获取变量长度的最简单方法是使用${#variable}
,而不是使用外部工具。请忽略这个答案;我很快就会删除它。我真丢脸!
要确定一个数字有多少位,您可以使用该数字以 10 为底的对数加一,然后去掉小数部分,但二进制计算器bc
有一个方便的函数可以做到这一点:
echo "length(334344)" | bc
将根据需要打印 6。如果 的参数length
不是整数,它将计算不带小数逗号的实际位数(即,length(3.4560)
将给出 5)。
echo
要在双引号内使用Bash 变量扩展插入 Bash 变量:
x=334344
echo "length($x)" | bc
我们可以将其写成一个函数以便于调用:
function num_digits {
#determine hoy many digits has a number
#param number
local number="$1"
echo "length($number)" | bc
}
然后按如下方式使用它:
lendigits=$(num_digits 334344)
或者,用一个变量
x=334344
lendigits=$(num_digits $x)
笔记:如果bc
您的 Linux 发行版中尚未安装,您可以使用发行版的包管理器添加它。
笔记2:当然,您可以直接使用表达式而不使用函数:
x=334344
lendigits=$(echo "length($x)" | bc)
但可读性较差,我更喜欢稍微长一点的脚本,其中识别特殊操作并将其封装在一个函数中,稍后我可以复制该函数以在其他脚本中使用。