Как написать скрипт, который работает с аргументами или без них?

У меня есть скрипт 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 без выдачи ошибки? Что я делаю не так?

13
задан 30 May 2016 в 16:31

5 ответов

"Надлежащий способ" использования долгих опций в сценариях оболочки через 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
ответ дан 23 November 2019 в 03:13

Несколько путей; самые очевидные два:

  • Помещенный $1 в двойных кавычках: if [ "$1" = "--test" ]
  • Проверка на количество аргументов с помощью $ #

Еще лучше, используйте getopts.

16
ответ дан 30 May 2016 в 16:31

Необходимо заключить переменные в кавычки в если условие. Замена:

if [ $1 = "--test" ] || [ $1 = "-t" ]; then

с:

if [ "$1" = '--test' ] || [ "$1" = '-t' ]; then  

Затем это будет работать:

вћњ ~./test.sh
, Не тестирующий.

Всегда всегда двойная кавычка Ваши переменные!

7
ответ дан 30 May 2016 в 16:31

Чтобы протестировать, если аргументы присутствуют (в целом, и делают действия соответственно), Это должно работать:

#!/bin/bash

check=$1

if [ -z "$check" ]; then
  echo "no arguments"
else echo "there was an argument"
fi
3
ответ дан 30 May 2016 в 16:31

Вы используете удар. 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

, Конечно, надлежащее заключение в кавычки должно всегда делаться, но нет никакой причины придерживаться с [ при использовании удара.

4
ответ дан 30 May 2016 в 16:31

Другие вопросы по тегам:

Похожие вопросы: