Была такая же проблема при выполнении Джессиapt upgrade
(при подготовке к удаленному -обновлению ).
Решение было просто
apt-get remove db5.1-util
Ваш цикл фактически зацикливается на первых элементах A
и B
, то есть ${A[0]}
и ${B[0]}
, что позже означает, что ${n[1]}
и ${n[2]}
будут пустыми строками, а ${n[0]}
— это то же, что $n
.
Я бы, вероятно, использовал переменную ссылки на имя, чтобы сделать это вbash
(версии 4.3 или более поздней):
#!/bin/bash
A=( 127.0.0.1 localhost alpha beta gamma theta )
B=( 8.8.8.8 dns itsy bitsy 'spider man' )
for variable in A B; do
declare -n array="$variable"
if ping -c3 "${array[0]}" >/dev/null; then
printf '%s\n' "${array[1]}"
printf '\t%s\n' "${array[@]:2}"
fi
done
Я перебираю имена переменных A
и B
, а не их содержимое. В цикле я создаю array
как ссылку имени на переменную с именем $variable
. Теперь array
используется точно так же, как A
или B
.
В операторе if
я не полагаюсь на то, что оболочка разбивает третий элемент массива для зацикливания. Вместо этого я разделяю его вручную при создании массивов A
и B
и просто вывожу эти элементы одним вызовом printf
, используя смещение в массиве array
. Я вывожу вкладку перед каждым элементом для удобства чтения.
localhost
alpha
beta
gamma
theta
dns
itsy
bitsy
spider man
Оператор if
можно также записать как
if ping -c3 "${array[0]}" >/dev/null; then
printf '%s: ' "${array[1]}"
( IFS=,; printf '%s\n' "${array[*]:2}" )
fi
для вывода остальных элементов массива в виде списка, разделенного запятыми -после двоеточия:
localhost: alpha,beta,gamma,theta
dns: itsy,bitsy,spider man
Примечание. :Ни одно из приведенных выше цитирований не является случайным. Заключение расширения массива гарантирует, что каждый элемент заключен в кавычки отдельно. Заключение раскрытия одного элемента в кавычки гарантирует, что оболочка не разбивает значение на пробелы (и не выполняет подстановку имен файлов на разделенные -слова вверх ).
См. также
Вы также можете сделать это с /bin/sh
без именованных массивов. Вместо этого мы используем список позиционных параметров для хранения наших данных и заканчиваем каждый раздел этого списка специальным словом (мы используем END
, это произвольная строка, которую мы выбираем ).Затем мы перебираем этот список и сдвигаем элементы из него по мере продвижения:
#!/bin/sh
set -- 127.0.0.1 localhost alpha beta gamma theta END \
8.8.8.8 dns itsy bitsy 'spider man' END
while [ "$#" -gt 0 ]; do
if ping -c 3 "$1" >/dev/null; then
printf '%s\n' "$2"
shift 2
while [ "$1" != END ]; do
printf '\t%s\n' "$1"
shift
done
else
while [ "$1" != END ]; do shift; done
fi
shift
done
for n in ${A} ${B} ; do
Это не то, что вы хотите. Взять массив без индекса — это то же самое, что взять элемент с нулевым индексом, поэтому ${A}
— это то же самое, что и ${A[0]}
, и то же самое для B
. Цикл устанавливает $n
в отдельные значения одно за другим, так что вы получите ${A[0]}
на первой итерации и ${B[0]}
на второй.
То же самое относится к ${n[0]}
, ${n[1]}
, ${n[2]}
и т. д. $n
не является массивом, поэтому только ${n[0]}
имеет какое-либо содержимое, остальные просто не заданы.
Bash на самом деле не работает с двумерными -массивами, но вы можете инвертировать эту структуру с помощью чего-то вроде этого:
ips=(127.0.0.1 8.8.8.8)
names=(localhost dns)
for i in "${!ips[@]}"; do
if ping -c3 "${ips[i]}"; then
echo "host ${names[i]-"(unknown")} is up"
fi
done
Но вам, вероятно, следует просто хранить данные в отдельном файле.
Обратите внимание, что все, что касается структур данных и циклов, может сильно отличаться в Zsh, а IIRC ksh также имеет лучшую поддержку структур данных, чем Bash.