У меня есть скрипт bash, который выглядит примерно так:
#!/bin/bash
if [ $1 = "--test" ] || [ $1 = "-t" ]; then
echo "Testing..."
testing="y"
else
testing="n"
echo "Not testing."
fi
Так что я хочу иметь возможность не только запускать его с ./script --test
или ./script -t
, но и без аргументы (просто ./script
), но, по-видимому, если я сделаю это с текущим кодом, результат будет просто:
./script: line 3: [: =: unary operator expected
./script: line 3: [: =: unary operator expected
Not testing.
Так как мне запрограммировать его так, чтобы запуск его без каких-либо аргументов вообще делал else
без выдачи ошибки? Что я делаю не так?
"Надлежащий способ" использования долгих опций в сценариях оболочки через getopt утилиту GNU. Существует также getopts, который является встроенным ударом, но он только позволяет короткие опции как -t
. Несколько примеров getopt
использование может быть найдено здесь.
Вот сценарий, который демонстрирует, как я приблизился бы к Вашему вопросу. Объяснение большинства шагов добавляется как комментарии в рамках самого сценария.
#!/bin/bash
# GNU getopt allows long options. Letters in -o correspond to
# comma-separated list given in --long.
opts=$(getopt -o t --long test -- "$*")
test $? -ne 0 && exit 2 # error happened
set -- $opts # some would prefer using eval set -- "$opts"
# if theres -- as first argument, the script is called without
# option flags
if [ "$1" = "--" ]; then
echo "Not testing"
testing="n"
# Here we exit, and avoid ever getting to argument parsing loop
# A more practical case would be to call a function here
# that performs for no options case
exit 1
fi
# Although this question asks only for one
# option flag, the proper use of getopt is with while loop
# That's why it's done so - to show proper form.
while true; do
case "$1" in
# spaces are important in the case definition
-t | --test ) testing="y"; echo "Testing" ;;
esac
# Loop will terminate if there's no more
# positional parameters to shift
shift || break
done
echo "Out of loop"
С несколькими упрощениями и удаленными комментариями, это может быть сжато к:
#!/bin/bash
opts=$(getopt -o t --long test -- "$*")
test $? -ne 0 && exit 2 # error happened
set -- $opts
case "$1" in
-t | --test ) testing="y"; echo "Testing";;
--) testing="n"; echo "Not testing";;
esac
Несколько путей; самые очевидные два:
$1
в двойных кавычках: if [ "$1" = "--test" ]
Еще лучше, используйте getopts.
Необходимо заключить переменные в кавычки в если условие. Замена:
if [ $1 = "--test" ] || [ $1 = "-t" ]; then
с:
if [ "$1" = '--test' ] || [ "$1" = '-t' ]; then
Затем это будет работать:
вћњ ~./test.sh
, Не тестирующий.
Всегда всегда двойная кавычка Ваши переменные!
Чтобы протестировать, если аргументы присутствуют (в целом, и делают действия соответственно), Это должно работать:
#!/bin/bash
check=$1
if [ -z "$check" ]; then
echo "no arguments"
else echo "there was an argument"
fi
Вы используете удар. Bash имеет большую альтернативу [
: [[
. С [[
, Вы не должны волноваться, получаете ли о заключении в кавычки, и Вы намного больше операторов, чем [
, включая надлежащую поддержку ||
:
if [[ $1 = "--test" || $1 = "-t" ]]
then
echo "Testing..."
testing="y"
else
testing="n"
echo "Not testing."
fi
Или можно использовать регулярные выражения:
if [[ $1 =~ ^(--test|-t) ]]
then
echo "Testing..."
testing="y"
else
testing="n"
echo "Not testing."
fi
, Конечно, надлежащее заключение в кавычки должно всегда делаться, но нет никакой причины придерживаться с [
при использовании удара.