У меня есть следующая функция bash, которая меня сбивает с толку. Если я ввожу следующее в поля zenity...
идентификатор сотрудника = 2 идентификатор категории = 3
Я получаю следующее: 2 3
если...
идентификатор сотрудника = идентификатор категории = 3
После того, как открывается второе окно zenity, я ввожу 2 и получаю следующее: 2 3
Однако, когда я вхожу
идентификатор_сотрудника = 2 идентификатор_категории =
Никакого дополнительного окна Zenity не открывается, и я получаю следующее: 2
На самом деле я хочу получить результат 2,3 после проведения тестов.
Кто-нибудь знает, в чем тут проблема?
#!/bin/bash
num(){
emp=$(echo "$1" | awk -F, -v OFS=, '{print $1 "," $2}')
IFS=, read -ra array1 <<<"$emp"
p=$(for i in "${array1[@]}"
do
if [[ "${i}" =~ ^[0-9]+$ ]]; then
out="${i}"
elif
[[ "${i}" = NULL ]]; then
out="${i}"
else local var2
until [[ ${var2} =~ ^[0-9]+$ ]] || [[ ${var2} = NULL ]]; do
var2="$(zenity --forms --title="table salaries_wages" --text "Add a number" --separator="," \
--add-entry="WARNING! You either forgot to enter or didn't enter a number. Please enter a valid number: ")"
done
out="${var2}"
fi
echo "$out"
done)
echo "$p"
}
input="$(zenity --forms --title="table salaries_wages" --text="Add a new salaries_wages entry" --separator="," \
--add-entry="ENTER employeeid: " \
--add-entry="ENTER categoryid: ")"
num "$input"
решение1
что здесь не так?
Ваше предположение о том, как это read
работает, отличается от того, как это read
работает на самом деле. Запустите этот код в Bash:
how_many () { IFS=, read -ra array1 <<<"$1"; echo "${#array1[@]}"; }
how_many "2,3"
how_many ",3"
how_many "2,"
Вы получите 2
, 2
, 1
. Последний номер выделяется. Это означает, что конечный разделитель ( ,
в данном случае) обрабатывается read
скорее как терминатор: пустое поле после него не считывается в массив, и массив оказывается на один элемент короче. Если это происходит в вашем коде, то for i in "${array1[@]}"
цикл будет запущен только для первого поля.
Решением может быть введениедополнительный ,
как завершающий терминатор намеренно. Тогда read
он никогда не будет читать третье поле, но всегда будет читать два поля (даже если второе пустое). Посмотрите на разницу, когда я добавляю дополнительный ,
:
how_many () { IFS=, read -ra array1 <<<"$1,"; echo "${#array1[@]}"; }
how_many "2,3"
how_many ",3"
how_many "2,"
how_many ","
Выход — 2
каждый раз.
Чтобы исправить код таким образом, используйте <<<"$emp,"
вместо <<<"$emp"
.
Если вы исправите код, то он будет вести себя неправильно, когда else
блок будет запущен более одного раза (т. е. когда оба поля изначально недействительны); потому что выповторное использование var2
переменнойснова.
Я полагаю, вы избегали local var2
этого, но local
делали переменную локальной в функции, а не в else
блоке или в одной итерации цикла for
. Вы повторно используете var2
в том же экземпляре функции num
.
Вы вызываете функцию один раз. Внутри она var2
всегда одна и та же var2
, local
только отличает ее от любой var2
за пределами этого самого вызова функции. Если вы использовали var2
за пределами функции, то тот, что в функции, будет отличаться. Если вы вызывали num
больше одного раза, каждый вызов будет использовать свой собственный different var2
. Ничего из этого не происходит. Вы вызываете функцию один раз и повторно используете переменнуютам. Если два поля недействительны, переменная используется для первого поля, а затемповторно использованныйдля второго поля.
Но если вы перестроите свой код так, чтобы некоторая функция (например validate
, ) вызывалась изнутри цикла:
for i in "${array1[@]}"; do validate "$i"; …
и использовать local var2
в validate
функции, то var2
при каждом вызове функции будет отличаться. Вот как local
может помочь. В каждом цикле validate
будет вызван заново, его локальная переменная(ые) будет инициализирована заново без какой-либо связи с другими переменными(ыми) с тем же именем(ями). Однако вы все равно сможете повторно использовать локальную переменнуювнутрифункцию таким образом, что это что-то ломает (аналогично тому, как вы сейчас повторно используете var2
функцию num
).
После того, как я написал выше, я добавил примеруже связанный ответ.
Примечание p=$(stuff); echo "$p"
почти эквивалентно echo "$(stuff)"
, которое почти всегда должно быть просто stuff
. Пожалуйста, прочтитеэтот ответгде подробно рассказывается о var=$(stuff); echo "$var"
.