Я слежу за этой темой: https://stackoverflow.com/a/19742842/5057251 для набора (или объявления) в ZSH, а не в BASH.
#Declare (or typeset) an array of integers
#declare -ai int_array
typeset -ai int_array
int_array=(1 2 3)
echo "${int_array[@]}"
потом
# Attempt to change 1st element to string. (expect to fail)
int_array[1] = "Should fail" || echo "error: ${LINENO}"
echo "${int_array[@]}"
Bash находит ошибку, изящно сообщает об ошибке и lineno, печатает:
1 2 3
Но Zsh принимает, печатает:
Should fail 2 3
Не знаю, почему по-другому.
Здесь есть две проблемы:
В bash и zsh присваивание строки целочисленной переменной приводит к тому, что эта строка оценивается как арифметическое выражение. Таким образом, это не ошибка:
$ typeset -i foo
$ foo = "bar"
Если бы bar
была переменной, ранее установленной в арифметическое выражение, то расширение bar
было бы оценено как таковое:
$ bar=10+2
$ typeset -i foo
$ foo = "bar"
$ echo "$foo"
12
Ошибка в вашем задании, конечно же, в том, что нет возможности так расширить Should fail
. Если бы это было, скажем, Should - fail
(например, арифметическое выражение, вычитающее значение двух переменных Should
и fail
, оно все равно работало бы:
$ foo = "Should - fail"
$ echo "$foo"
0
Вторая проблема заключается в том, что ничто в документы зш не указывает на то, что -i
может быть установлено для всего массива, поэтому -a
в -ai
игнорируется:
bash-5.0$ typeset -ai foo
bash-5.0$ declare -p foo
declare -ai foo=([0] = "0") # the previous value was retained in the array
против ЗШ:
% typeset -ai foo
% foo[1]=10
% foo[2]=20
% declare -p foo
typeset -i foo=20 # treated as a normal variable, not array
То, что вы видите, по сути int_array
переобъявляется как массив (без каких-либо квалификаторов), когда вы делаете int_array=(1 2 3)
:
% foo=(1 2 3)
% declare -p foo
typeset -a foo=( 1 2 3 )
Использование zsh typeset может дать несколько возможных результатов:
- ошибок нет, работает (ага!).
- ошибки, сбой скрипта (исправить!).
- ошибок нет, но поведение непредвиденный. (почесать голову)
В качестве примера последней категории это не приводит к ошибкам, но typeset -p
показывает, что -i игнорируется.
{
unset int_array
typeset -ia int_array
int_array=(1 2 3)
echo $? "-Point A"
typeset -p int_array
} always {
echo $? "-Point B"
typeset -p int_array
(( TRY_BLOCK_ERROR=0 ))
}
echo $? "-Point C"
echo "survived"
производит
0 -Point A
typeset -a int_array=( 1 2 3 )
0 -Point B
typeset -a int_array=( 1 2 3 )
0 -Point C
survived
Первая строка сбрасывает int_array. Команда набора объявляет
int_array должен быть как массивом, так и целым, что не позволяет zsh. Следующий
строка присваивает int_array значение. Как говорит нам $?
, ошибки нет,
но внимательное изучение финала typeset -p int_array
показывает, что на самом деле
случилось.
С небольшим изменением мы можем выдавать ошибки и использовать блок always
и typeset -p
чтобы узнать подробности.
{
unset int_array
typeset -ia int_array=(1 2 3) # error
echo $? "-Point A"
typeset -p int_array
} always {
echo $? "-Point B"
typeset -p int_array
(( TRY_BLOCK_ERROR=0 ))
}
echo $? "-Point C"
echo "survived"
040_declare_version2.sh:typeset:135: int_array: inconsistent type for assignment
1 -Point B
040_declare_version2.sh:typeset:140: no such variable: int_array
1 -Point C
survived
Единственная разница в том, что int_array было присвоено значение в ошибочном операторе typeset -ia
.
Это приводит к ошибкам, и скрипт переходит к always block.
(( TRY_BLOCK_ERROR=0))
позволяет продолжить выполнение сценария
и не прекращается, но об ошибке все еще сообщается в «точке C».
Чтобы проверить версию оболочки:
$SHELL --version
zsh 5.4.2 (x86_64-ubuntu-linux-gnu)
Сложный.
declare -p foo
# очень полезно посмотреть, что думает оболочка