Ответ 1
Bash не поддерживает многомерные массивы. Попробуйте
array=(a b c d)
echo ${array[1]}
echo ${array[1][3]}
echo ${array[1]exit}
Для трюков, как имитировать их, см. Расширенные Bash Руководство по сценариям.
Я пытаюсь прочитать строку ввода строки за строкой, которая содержит поля, разделенные периодами. Я хочу поместить их в массив массивов, чтобы потом перебирать их. Ввод выглядит нормально, но "нажатие" на массив (inData) не работает.
Код идет:
Input file:
GSDB.GOSALESDW_DIST_INVENTORY_FACT.MONTH_KEY
GSDB.GOSALESDW_DIST_INVENTORY_FACT.ORGANIZATION_KEY
infile=${1}
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
Bash не поддерживает многомерные массивы. Попробуйте
array=(a b c d)
echo ${array[1]}
echo ${array[1][3]}
echo ${array[1]exit}
Для трюков, как имитировать их, см. Расширенные Bash Руководство по сценариям.
Поле гнезда поля в bash, но оно не может обойти этот пример.
declare -a pages
pages[0]='domain.de;de;https'
pages[1]='domain.fr;fr;http'
for i in "${pages[@]}"
do
arr=(${i//;/ })
site=${arr[0]}
language=${arr[1]}
protocol=${arr[2]}
done
Зная, что вы можете разделить строку на "массив". Вы можете создать список списков. Например, список баз данных на серверах БД.
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
Результат выше:
----
db001
--
app001
app002
app003
----
db002
--
app004
app005
----
dbcentral
--
central
Я боролся с этим, но нашел неудобный компромисс. В общем случае, столкнувшись с проблемой, решение которой связано с использованием структур данных в Bash, вы должны переключиться на другой язык, например Python. Игнорируя этот совет и двигаясь прямо:
Мои варианты использования обычно включают списки списков (или массивы массивов) и перебирают их. Обычно вы не хотите гнездиться гораздо глубже, чем это. Кроме того, большинство массивов представляют собой строки, которые могут содержать или не содержать пробелы, но обычно не содержат специальных символов. Это позволяет мне использовать несовместимый синтаксис для выражения внешнего массива, а затем использовать обычную обработку bash для строк, чтобы получить второй список или массив. Вам нужно будет обратить внимание на ваш IFS-разделитель, obvi.
Таким образом, ассоциативные массивы могут дать мне способ создать список списков, например:
declare -A JOB_LIST=(
[job1] = "a set of arguments"
[job2] = "another different list"
...
)
Это позволяет вам перебирать оба массива, например:
for job in "${!JOB_LIST[@]}"; do
/bin/jobrun ${job[@]}
done
Ah, за исключением того, что вывод списка ключей (с помощью магического ${!...}
) означает, что вы не будете перемещать ваш список по порядку. Поэтому еще один необходимый хак - сортировать порядок ключей, если это важно для вас. Порядок сортировки зависит от вас; Мне удобно пользоваться буквенно-цифровой сортировкой, и прибегать к aajob1 bbjob3 ccjob6
вполне приемлемо.
Поэтому
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
Вы можете использовать (de) ссылки на массивы, как в этом script:
#!/bin/bash
OFS=$IFS # store field separator
IFS="${2: }" # define field separator
file=$1 # 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