Arrays 获取Bash数组中值的索引
我在Arrays 获取Bash数组中值的索引,arrays,bash,indexing,Arrays,Bash,Indexing,我在bash中有类似的东西 myArray=('red' 'orange' 'green') 我想做一些类似的事情 echo ${myArray['green']} 在这种情况下,将输出2。这是可以实现的吗?否。您只能在bash中使用整数对简单数组进行索引。关联数组(在bash4中引入)可以通过字符串进行索引。但是,如果没有特殊构造的关联数组,它们不会提供您所要求的反向查找类型 $ declare -A myArray $ myArray=([red]=0 [orange]=1 [green
bash
中有类似的东西
myArray=('red' 'orange' 'green')
我想做一些类似的事情
echo ${myArray['green']}
在这种情况下,将输出
2
。这是可以实现的吗?否。您只能在bash
中使用整数对简单数组进行索引。关联数组(在bash
4中引入)可以通过字符串进行索引。但是,如果没有特殊构造的关联数组,它们不会提供您所要求的反向查找类型
$ declare -A myArray
$ myArray=([red]=0 [orange]=1 [green]=2)
$ echo ${myArray[green]}
2
这可以做到:
#!/bin/bash
my_array=(red orange green)
value='green'
for i in "${!my_array[@]}"; do
if [[ "${my_array[$i]}" = "${value}" ]]; then
echo "${i}";
fi
done
显然,如果将其转换为函数(例如get_index()),则可以将其设置为通用的
declare -A myArray
myArray=([red]=1 [orange]=2 [green]=3)
echo ${myArray['orange']}
还有一个棘手的方法:
echo ${myArray[@]/green//} | cut -d/ -f1 | wc -w | tr -d ' '
你得到2分
我喜欢这个解决方案:
let "n=(`echo ${myArray[@]} | tr -s " " "\n" | grep -n "green" | cut -d":" -f 1`)-1"
my_array=(red orange green)
echo ${my_array[*]} | tr ' ' '\n' | awk '/green/ {print NR-1}'
变量n将包含结果 这只是另一种初始化关联数组的方法,如切普纳所示。 不要忘记,您需要显式地
声明或使用-A
属性设置关联数组
i=0; declare -A myArray=( [red]=$((i++)) [orange]=$((i++)) [green]=$((i++)) )
echo ${myArray[green]}
2
这样就不需要硬编码值,并且不太可能得到重复的值
如果要添加很多值,那么将它们放在单独的行中可能会有所帮助
i=0; declare -A myArray;
myArray+=( [red]=$((i++)) )
myArray+=( [orange]=$((i++)) )
myArray+=( [green]=$((i++)) )
echo ${myArray[green]}
2
假设你想要一个数字和小写字母的数组(例如:用于菜单选择),你也可以这样做
declare -a mKeys_1=( {{0..9},{a..z}} );
i=0; declare -A mKeys_1_Lookup; eval mKeys_1_Lookup[{{0..9},{a..z}}]="$((i++))";
如果你然后跑
echo "${mKeys_1[15]}"
f
echo "${mKeys_1_Lookup[f]}"
15
这可能只适用于阵列
my_array=(red orange green)
echo "$(printf "%s\n" "${my_array[@]}")" | grep -n '^orange$' | sed 's/:orange//'
输出:
2
如果要在tsv文件中查找头索引
head -n 1 tsv_filename | sed 's/\t/\n/g' | grep -n '^header_name$' | sed 's/:header_name//g'
在zsh中,您可以执行以下操作
xs=( foo bar qux )
echo ${xs[(ie)bar]}
请参阅zshparam(1)小节下标标志,它更简洁一些,在Bash 3.x中可用:
my_array=(red orange green)
value='green'
for i in "${!my_array[@]}"; do
[[ "${my_array[$i]}" = "${value}" ]] && break
done
echo $i
另一个棘手的问题是:
index=$((-1 + 10#0$(IFS=$'\n' echo "${my_array[*]}" | grep --line-number --fixed-strings -- "$value" | cut -f1 -d:)))
特点:
- 支持带有空格的图元
- 未找到时返回
-1
注意事项:
- 要求
值
为非空
- 难懂
按执行顺序分解说明:
IFS=$'\n' echo "${my_array[*]}"
IFS=$'\n' [...] <<< "${my_array[*]}"
将数组扩展分隔符(IFS
)设置为新行字符并扩展数组
grep --line-number --fixed-strings -- "$value"
awk "\$0 == \"${value//\"/\\\"}\" {print NR-1}"
格雷普比赛:
- 显示行号(
--行号
或-n
)
- 使用固定字符串(
--fixed strings
或-F
;禁用正则表达式)
- 允许以
-
开头的元素(-
)
切割-f1-d:
仅提取行号(格式为:
)
减去1,因为行号是1索引的,而数组是0索引的
- 如果
$(…)
不匹配:
- 不返回任何内容&使用默认值
0
(10#0
)
- 如果
$(…)
匹配:
- 存在行号&前缀为
10#0
;i、 e.10#02
,10#09
,10#014
,等等
10 #
前缀强制使用10进制/十进制数字,而不是八进制数字
使用awk
代替grep
,cut
&bash算法:
IFS=$'\n'; awk "\$0 == \"${value//\"/\\\"}\" {print NR-1}" <<< "${my_array[*]}"
将数组扩展分隔符(IFS
)设置为新行字符并扩展数组
grep --line-number --fixed-strings -- "$value"
awk "\$0 == \"${value//\"/\\\"}\" {print NR-1}"
匹配整行并打印0索引行号
${value/\“/\\\”}
用转义版本替换$value
中的双引号
- 因为我们需要变量替换,所以这个段的转义比我们想要的要多
简单解决方案:
let "n=(`echo ${myArray[@]} | tr -s " " "\n" | grep -n "green" | cut -d":" -f 1`)-1"
my_array=(red orange green)
echo ${my_array[*]} | tr ' ' '\n' | awk '/green/ {print NR-1}'
这将输出查询的基于0的数组索引(此处为“橙色”)
echo$($(printf“%s\n”“${myArray[@]}”sed-n'/^orange$/{=;q}')-1))
如果查询未在数组中出现,则上述输出-1
如果查询在数组中多次出现,则上面的输出查询第一次出现的索引
由于该解决方案调用了sed,我怀疑它能否在效率上与该线程中的一些纯bash解决方案竞争。这展示了一些返回数组成员索引的方法。
数组对第一个和最后一个索引使用不适用的值,
提供从1开始的索引,并提供限制
while循环是一种有趣的迭代方法,
为了生成数组值的索引,
循环体仅包含一个用于null操作的冒号。
重要的是迭代i直到匹配,
或者超过可能的匹配项
函数indexof()将文本值转换为索引。
如果某个值不匹配,则函数返回一个错误代码,该错误代码可能是
在测试中用于执行错误处理。
与数组不匹配的输入值将超过范围限制(-gt,-lt)
测试
有一个测试(主代码)循环好/坏的值,前3行被注释掉,但尝试一些变化以查看有趣的结果(第1、3或2、3或4行
)。我包含了一些考虑错误条件的代码,因为它可能很有用
最后一行代码使用已知的良好值“green”调用函数indexof,该值将回显索引值
indexof(){
local s i;
# 0 1 2 3 4
s=( @@@ red green blue @o@ )
while [ ${s[i++]} != $1 ] && [ $i -lt ${#s[@]} ]; do :; done
[ $i -gt 1 ] && [ $i -lt ${#s[@]} ] || return
let i--
echo $i
};# end function indexof
# --- main code ---
echo -e \\033c
echo 'Testing good and bad variables:'
for x in @@@ red pot green blue frog bob @o@;
do
#v=$(indexof $x) || break
#v=$(indexof $x) || continue
#echo $v
v=$(indexof $x) && echo -e "$x:\t ok" || echo -e "$x:\t unmatched"
done
echo -e '\nShow the index of array member green:'
indexof green
我自己也想要类似的东西,避免循环,想出了
myArray=('red' 'orange' 'green')
declare -p myArray | sed -n "s,.*\[\([^]]*\)\]=\"green\".*,\1,p"
。。。如果找不到元素,stdout就不会被污染
$ myArray=('red' 'orange' 'green')
$ declare -p myArray | sed -n "s,.*\[\([^]]*\)\]=\"green\".*,\1,p"
2
$ declare -p myArray | sed -n "s,.*\[\([^]]*\)\]=\"gren\".*,\1,p"
$
之后,我在谷歌上搜索,发现了这个问题,并想与大家分享;) 我的第一个建议是使用python而不是bash编写脚本。一旦我开始这么做,我就再也不回头了。谢谢你,我知道我可以用python字典轻松地做到这一点,但这不是我想要的。这不适用于稀疏数组或关联数组。要使其适用于所有类型的数组,请将C样式的for循环替换为:“${!my_array[@]}”中的i的;执行
。另外,如果您只想找到第一个索引,那么如果找到了索引,您可能需要中断循环。请您解释一下是什么
在${!我的数组[@]}
?@bodacydo中的意思,我想知道
的意思也是,然后尝试了一下,发现它没有列出数组中的所有值,而是