bash bash中的数组数组
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12317483/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Array of arrays in bash
提问by jaybee
I'm attempting to read an input file line by line which contains fields delimited by periods. I want to put them into an array of arrays so I can loop through them later on. The input appears to be ok, but 'pushing' that onto the array (inData) doesn't appear to be working.
我正在尝试逐行读取包含以句点分隔的字段的输入文件。我想将它们放入一个数组数组中,以便稍后我可以遍历它们。输入似乎没问题,但将其“推送”到数组 (inData) 上似乎不起作用。
The code goes :
代码如下:
Input file:
GSDB.GOSALESDW_DIST_INVENTORY_FACT.MONTH_KEY
GSDB.GOSALESDW_DIST_INVENTORY_FACT.ORGANIZATION_KEY
infile=
OIFS=$IFS
IFS=":"
cat ${infile} | while read line
do
line=${line//\./:}
inarray=(${line})
# echo ${inarray[@]}
# echo ${#inarray[@]}
# echo ${inarray[0]}
# echo ${inarray[1]}
# echo ${inarray[2]}
inData=("${inData[@]}" "${inarray[@]}")
done
IFS=$OIFS
echo ${#inData[@]}
for ((i = 0; i < ${#inData[@]}; i++))
do
echo $i
for ((j = 0; j < ${#inData[$i][@]}; j++))
do
echo ${inData[$i][$j]}
done
done
采纳答案by choroba
Bash has no support for multidimensional arrays. Try
Bash 不支持多维数组。尝试
array=(a b c d)
echo ${array[1]}
echo ${array[1][3]}
echo ${array[1]exit}
For tricks how to simulate them, see Advanced Bash Scripting Guide.
有关如何模拟它们的技巧,请参阅高级 Bash 脚本指南。
回答by Luká? K?í?
Field nest box in bash but it can not circumvent see the example.
bash 中的字段嵌套框但它无法绕过查看示例。
#!/bin/bash
# requires bash 4 or later; on macOS, /bin/bash is version 3.x,
# so need to install bash 4 or 5 using e.g. https://brew.sh
declare -a pages
pages[0]='domain.de;de;https'
pages[1]='domain.fr;fr;http'
for page in "${pages[@]}"
do
# turn e.g. 'domain.de;de;https' into
# array ['domain.de', 'de', 'https']
IFS=";" read -r -a arr <<< "${page}"
site="${arr[0]}"
lang="${arr[1]}"
prot="${arr[2]}"
echo "site : ${site}"
echo "lang : ${lang}"
echo "prot : ${prot}"
echo
done
回答by Nux
Knowing that you can split string into "array". You could creat a list of lists. Like for example a list of databases in DB servers.
知道您可以将字符串拆分为“数组”。您可以创建一个列表列表。例如,数据库服务器中的数据库列表。
dbServersList=('db001:app001,app002,app003' 'db002:app004,app005' 'dbcentral:central')
# Loop over DB servers
for someDbServer in ${dbServersList[@]}
do
# delete previous array/list (this is crucial!)
unset dbNamesList
# split sub-list if available
if [[ $someDbServer == *":"* ]]
then
# split server name from sub-list
tmpServerArray=(${someDbServer//:/ })
someDbServer=${tmpServerArray[0]}
dbNamesList=${tmpServerArray[1]}
# make array from simple string
dbNamesList=(${dbNamesList//,/ })
fi
# Info
echo -e "\n----\n$someDbServer\n--"
# Loop over databases
for someDB in ${dbNamesList[@]}
do
echo $someDB
done
done
Output of above would be:
上面的输出将是:
----
db001
--
app001
app002
app003
----
db002
--
app004
app005
----
dbcentral
--
central
回答by The Big Baba
I struggled with this but found an uncomfortable compromise. In general, when faced with a problem whose solution involves using data structures in Bash, you should switch to another language like Python. Ignoring that advice and moving right along:
我为此苦苦挣扎,但找到了一个不舒服的妥协。通常,当遇到解决方案涉及在 Bash 中使用数据结构的问题时,您应该切换到另一种语言,如 Python。忽略该建议并继续前进:
My use cases usually involve lists of lists (or arrays of arrays) and looping over them. You usually don't want to nest much deeper than that. Also, most of the arrays are strings that may or may not contain spaces, but usually don't contain special characters. This allows me to use not-to-confusing syntax to express the outer array and then use normal bash processing on the strings to get a second list or array. You will need to pay attention to your IFS delimiter, obvi.
我的用例通常涉及列表列表(或数组数组)并循环遍历它们。你通常不想嵌套得比这更深。此外,大多数数组都是字符串,可能包含也可能不包含空格,但通常不包含特殊字符。这允许我使用不会混淆的语法来表达外部数组,然后对字符串使用正常的 bash 处理来获得第二个列表或数组。您需要注意您的 IFS 分隔符,obvi。
Thus, associative arrays can give me a way to create a list of lists like:
因此,关联数组可以为我提供一种创建列表列表的方法,例如:
declare -A JOB_LIST=(
[job1] = "a set of arguments"
[job2] = "another different list"
...
)
This allows you to iterate over both arrays like:
这允许您遍历两个数组,例如:
for job in "${!JOB_LIST[@]}"; do
/bin/jobrun ${job[@]}
done
Ah, except that the output of the keys list (using the magical ${!...}
) means that you will not traverse your list in order. Therefore, one more necessary hack is to sort the order of the keys, if that is important to you. The sort order is up to you; I find it convenient to use alphanumerical sorting and resorting to aajob1 bbjob3 ccjob6
is perfectly acceptable.
啊,除了键列表的输出(使用魔法${!...}
)意味着您不会按顺序遍历您的列表。因此,另一个必要的技巧是对键的顺序进行排序,如果这对您很重要的话。排序顺序由您决定;我发现使用字母数字排序很方便,并且aajob1 bbjob3 ccjob6
完全可以接受。
Therefore
所以
declare -A JOB_LIST=(
[aajob1] = "a set of arguments"
[bbjob2] = "another different list"
...
)
sorted=($(printf '%s\n' "${!JOB_LIST[@]}"| /bin/sort))
for job in "${sorted[@]}"; do
for args in "${job[@]}"; do
echo "Do something with ${arg} in ${job}"
done
done
回答by oobash
I use Associative Arrays and use :: in the key to denote depth. The :: can also be used to embed attributes, but that is another subject,...
我使用关联数组并在键中使用 :: 来表示深度。:: 也可用于嵌入属性,但那是另一个主题,...
declare -A __myArrayOfArray=([Array1::Var1]="Assignment" [Array2::Var1]="Assignment")
An Array under Array1
Array1 下的数组
__myArrayOfArray[Array1::SubArray1::Var1]="Assignment"
The entries in any array can be retrieved (in order ...) by ...
任何数组中的条目都可以通过...检索(按...)
local __sortedKeys=`echo ${!__myArrayOfArray[@]} | xargs -n1 | sort -u | xargs`
for __key in ${__sortedKeys}; do
#
# show all properties in the Subordinate Profile "Array1::SubArray1::"
if [[ ${__key} =~ ^Array1::SubArray1:: ]]; then
__property=${__key##Array1::SubArray1::}
if [[ ${__property} =~ :: ]]; then
echo "Property ${__property%%:*} is a Subordinate array"
else
echo "Property ${__property} is set to: ${__myArrayOfArray[${__key}]}"
fi
fi
done
THE list of subordinate "Profiles" can be derived by:
从属“配置文件”列表可以通过以下方式导出:
declare -A __subordinateProfiles=()
local __profile
local __key
for __key in "${!__myArrayOfArray[@]}"; do
if [[ $__key =~ :: ]]; then
local __property=${__key##*:}
__profile=${__key%%:*}
__subordinateProfiles[${__profile}]=1
fi
done
回答by setempler
You could make use of (de)referencing arrays like in this script:
您可以像在此脚本中一样使用(取消)引用数组:
#!/bin/bash
OFS=$IFS # store field separator
IFS="${2: }" # define field separator
file= # input file name
unset a # reference to line array
unset i j # index
unset m n # dimension
### input
i=0
while read line
do
a=A$i
unset $a
declare -a $a='($line)'
i=$((i+1))
done < $file
# store number of lines
m=$i
### output
for ((i=0; i < $m; i++))
do
a=A$i
# get line size
# double escape '\' for sub shell '``' and 'echo'
n=`eval echo \${#$a[@]}`
for (( j = 0; j < $n; j++))
do
# get field value
f=`eval echo \${$a[$j]}`
# do something
echo "line $((i+1)) field $((j+1)) = '$f'"
done
done
IFS=$OFS