Я новичок в сценариях Bash, у меня гораздо больше опыта работы с языками C-типа. Я написал несколько сценариев с условным условием, которое проверяет значение неинстанцированной переменной и, если она не существует или соответствует значению, устанавливает переменную. Кроме того, все это в цикле for. Что-то вроде этого:

for i in ${!my_array[@]}; do 
   if [ "${my_array[i]}" = true ] 
   then
      #do something
   else
      my_array[i]=true;
   fi
done

Это может привести к сбою через нулевой указатель в Java, так как my_array [i] не создается до тех пор, пока он не будет проверен. Это хорошая практика в Bash? Мой сценарий работает так, как я задумал, но я понял, что тот факт, что kluge работает сейчас, не означает, что он будет работать в будущем.

Спасибо!

0
user1509130 28 Май 2019 в 17:29

2 ответа

Лучший ответ

По умолчанию ссылка на неопределенные (или «неустановленные») имена переменных в сценариях оболочки просто дает пустую строку. Но есть исключение: если оболочка запускается с опцией -u или set -u запускается в ней, расширения неустановленных переменных рассматриваются как ошибки и (если оболочка не является интерактивной) вызывают ее выйти. Bash также применяет этот принцип к элементам массива:

$ array=(zero one two)
$ echo "${array[3]}"

$ echo "array[3] = '${array[3]}'"
array[3] = ''
$ set -u
$ echo "array[3] = '${array[3]}'"
-bash: array[3]: unbound variable

Существуют также модификаторы, которые можно использовать для управления действиями расширения, если переменная (или элемент массива) не определена и / или пуста (определена как пустая строка):

$ array=(zero one '')
$ echo "array[2] is ${array[2]-unset}, array[3] is ${array[3]-unset}"
array[2] is , array[3] is unset
$ echo "array[2] is ${array[2]:-unset or empty}, array[3] is ${array[3]:-unset or empty}"
array[2] is unset or empty, array[3] is unset or empty

Существует множество других вариантов, см. стандарт синтаксиса оболочки POSIX, раздел 2.6.2 (Расширение параметров).

Кстати, вам нужно использовать фигурные скобки (как я делал выше) вокруг чего-либо, кроме простой ссылки на переменную. $name[2] является ссылкой на обычную переменную name (или элемент 0, если это массив), за которой следует строка "[2]"; ${name[2]}, с другой стороны, является ссылкой на элемент 2 массива name. Кроме того, вы почти всегда хотите обернуть ссылки на переменные в двойные кавычки (или включить их в строки в двойных кавычках), чтобы предотвратить «полезное» разбиение оболочки на слова и / или расширение их в списки соответствующих файлов. Например, этот тест:

if [ $my_array[i] = true ]

(в основном) эквивалентно:

if [ ${my_array[0]}[i] = true ]

... что совсем не то, что вы хотите. Но этот:

if [ ${my_array[i]} = true ]

Все еще не работает, потому что если my_array[i] не установлен (или пуст), он расширится до эквивалента:

if [ = true ]

... это неверный синтаксис тестовых выражений. Вы хотите это:

if [ "${my_array[i]}" = true ]
0
Gordon Davisson 28 Май 2019 в 16:56

вы найдете эту страницу по расширению параметров. полезно, а также этот по условностям.

Простой способ проверить переменную - проверить ее на ненулевую длину.

if [[ -n "$var" ]]
then : do stuff ...

Мне также нравится делать роковым доступ к несуществующей переменной; это означает дополнительную работу, но лучшую безопасность.

set -u # unset vars are fatal to access without exception handling
if [[ -n "${var:-}" ]] # handles unset during check
then : do stuff ...
1
Paul Hodges 28 Май 2019 в 16:41