Ошибка Bash throws, строка 8: $ 1: несвязанная переменная

15

Я пытаюсь научиться использовать getopts, чтобы у меня могли быть сценарии с анализируемым вводом (хотя я думаю, что getopts мог бы быть лучше). Я пытаюсь просто написать простой скрипт, чтобы вернуть процент использования разделов. Проблема в том, что одной из моих функций bash, похоже, не нравится то, что я называю $1переменной внутри функции. Я ссылаюсь на $1это потому, что get_percentфункции можно передать точку монтирования в качестве необязательного аргумента для отображения вместо всех точек монтирования.

Сценарий

#!/usr/bin/bash

set -e
set -u
set -o pipefail

get_percent(){
    if [ -n "$1" ] 
    then
        df -h $1 | tail -n +2 | awk '{ print $1,"\t",$5 }'
    else
        df -h | tail -n +2 | awk '{ print $1,"\t",$5 }'
    fi
}

usage(){
    echo "script usage: $(basename $0) [-h] [-p] [-m mount_point]" >&2
}

# If the user doesn't supply any arguments, we run the script as normal
if [ $# -eq 0 ];
then
    get_percent
    exit 0
fi
# ...

Выход

$ bash thing.sh
thing.sh: line 8: $1: unbound variable

$ bash -x thing.sh
+ set -e
+ set -u
+ set -o pipefail
+ '[' 0 -eq 0 ']'
+ get_percent
thing.sh: line 8: $1: unbound variable
Тимоти Пулиам
источник
Я не думаю, что это имеет какое-либо отношение getopts, не так ли? Ваш сценарий завершается из-за -uперед вызовом getopts.
ilkkachu
@ikkachu нет, наверное, нет. Но я не уверен, что смогу изменить название сейчас.
Тимоти Пулиам
Под сообщением должен быть небольшой текст для редактирования, прямо под тегами в вопросе
ilkkachu

Ответы:

29

set -uбудет прервана точно так, как вы описали, если вы ссылаетесь на переменную, которая не была установлена. Вы вызываете свой сценарий без аргументов, поэтому get_percentон вызывается без аргументов, что приводит $1к невозможности его установки.

Либо проверьте это перед вызовом вашей функции, либо используйте расширения по умолчанию ( ${1-default}расширится до, defaultесли еще не установлено что-то еще).

DopeGhoti
источник
Я подозревал это, но я не мог придумать, как обойти это. Расширение по умолчанию, кажется, исправило это. Большое спасибо!
Тимоти Пулиам
7
В частности, можно использовать [ -n "${1-}" ](то есть с пустым значением по умолчанию), чтобы увидеть, установлен ли параметр и не является ли он пустым; или [ "${1+x}" = x ]посмотреть, установлен ли он, даже если он пуст.
ilkkachu
Я все еще получаю несвязанную ошибку переменной несмотря на использованиеif [[ -n ${1-default} ]]
Чайтанья
6

Это эффект set -u.

Вы можете проверить $#внутри функции и избежать ссылки, $1если она не установлена.

С помощью $#вы можете получить доступ к ряду параметров. В глобальном контексте это количество параметров для скрипта, в функции это количество параметров для функции.

В контексте вопроса это

if [ $# -ge 1 ] && [ -n "$1" ]
then
    df -h $1 | tail -n +2 | awk '{ print $1,"\t",$5 }'
else
    df -h | tail -n +2 | awk '{ print $1,"\t",$5 }'
fi

Обратите внимание, что вы должны использовать, [ $# -ge 1 ] && [ -n "$1" ]а не [ $# -ge 1 -a -n "$1" ], потому что это будет сначала оценить, $1а затем проверить $#.

RalfFriedl
источник
Можете ли вы объяснить больше, как использовать $ # и как это проверить? Спасибо
Чайтанья
1
Я добавил пример.
Ральф Фридл
3

Так как это bashвы можете обойти проверку на предмет $1установки и просто использовать "$@"( $1это первый параметр, $@это все из них; при двойных кавычках он исчезает полностью, если у него нет значений, что позволяет избежать его захвата set -u):

get_percent() {
    df -h "$@" | awk 'NR>1 { printf "%s\t%s\n", $1, $5 }'
}

Я также немного подправил остальную часть строки, чтобы вы не получили {пробел} {табуляцию} {пробел} между двумя значениями, которые вы выводите, но вместо этого вы получаете просто {табуляцию}. Если вы действительно хотите два невидимых пространства, измените их awkна использование printf "%s \t %s\n", $1, $5.

roaima
источник
Я должен буду изучить это. Я не знаком с этим типом переменной. Спасибо
Тимоти Пулиам
@TimothyPulliam Я добавил $@для тебя краткое объяснение
roaima