Проверьте, соответствует ли какой-либо из параметров скрипта bash строке

67

Я пытаюсь написать скрипт, в котором я хочу проверить, соответствует ли какой-либо из параметров, переданных скрипту bash, строке. То, как я сейчас это настроил,

if [ "$3" != "-disCopperBld" -a "$4" != "-disCopperBld" -a "$5" != "-disCopperBld" -a "$6" != "-disCopperBld"]

но может быть большое количество параметров, поэтому мне было интересно, есть ли лучший способ сделать это?

Спасибо

РЕДАКТИРОВАТЬ: я попробовал этот кусок кода, и вызвал сценарий с параметром -disableVenusBld, но он по-прежнему выводит «Начиная сборку». Я делаю что-то неправильно? Заранее спасибо!

while [ $# -ne 0 ]
do
    arg="$1"
    case "$arg" in
        -disableVenusBld)
            disableVenusBld=true
            ;;
        -disableCopperBld)
            disableCopperBld=true
            ;;
        -disableTest)
            disableTest=true
            ;;
        -disableUpdate)
            disableUpdate=true
            ;;
        *)
            nothing="true"
            ;;
    esac
    shift
done

if [ "$disableVenusBld" != true ]; then
    echo "Starting build"
fi
iman453
источник
Спасибо за ответы, ребята, я ценю, что вы нашли время, чтобы помочь мне. Я попробовал кусок кода, но я не могу понять, что происходит не так. Есть идеи? (Я вставил код в редактирование моего оригинального сообщения)
iman453
Хм: это работает для меня. Я добавил #! /bin/sh -в начало того, что вы там включили, сделал исполняемый скрипт, затем ./t.shнапечатал «Starting build», но ./t.sh -disableVenusBldничего не печатал.
Норман Грей

Ответы:

59

Похоже, вы выполняете обработку опций в скрипте оболочки. Вот идиома для этого:

#! /bin/sh -

# idiomatic parameter and option handling in sh
while test $# -gt 0
do
    case "$1" in
        --opt1) echo "option 1"
            ;;
        --opt2) echo "option 2"
            ;;
        --*) echo "bad option $1"
            ;;
        *) echo "argument $1"
            ;;
    esac
    shift
done

exit 0

(Есть несколько соглашений для отступа ;;, и некоторые оболочки позволяют вам давать варианты как (--opt1), чтобы помочь с сопоставлением скобок, но это основная идея)

Норман грей
источник
3
shiftОператор используется , когда число аргументов команды не известно заранее, например , когда пользователь может дать столько аргументов , сколько им нравится. В таких случаях аргументы обрабатываются в whileцикле с условием проверки $#. Это условие выполняется до тех пор, пока количество аргументов больше нуля. $1Переменная и shiftоператор обрабатывает каждый аргумент. Число аргументов уменьшается каждый раз, когда shiftвыполняется, и в итоге становится равным нулю, после чего whileцикл завершается. источник
Серж Штробандт
Вот аналогичный пример с дополнительной echo $1 | sedобработкой значения аргумента .
Серж Строобандт
26

Это сработало для меня. Он делает именно то, что вы просили, и ничего более (без обработки опций). Хорошо это или плохо - упражнение для плаката :)

if [[ "$*" == *YOURSTRING* ]]
then
    echo "YES"
else
    echo "NO"
fi

Это использует преимущества специальной обработки $* и супер-теста bash [[]]скобок.

Рич Гомолка
источник
2
ИМХО это должен был быть самый правильный ответ, так как вопрос требует только проверки наличия параметра. Я отредактировал, однако, изменив $*на $@, так как тестируемая строка может иметь пробелы и добавить ссылку на документацию bash об этом.
h7r
9
Вы хотели использовать оператор = ~? В противном случае я не понимаю, почему это должно работать, и действительно, это не работает, когда я пробую точный сценарий.
Сеппо Энарви
3
Не работает. bash -c 'echo args=$*; [[ "$@" == "bar" ]] && echo YES || echo NO' -- foo bar
Тобиа
2
Это сравнивает весь список аргументов с your string. Я думаю, что вам нужно сделать то, что предлагает этот ответ . т.е. bash -c 'echo args=$*; for i in "$@" ; do [[ $i == "bar" ]] && echo "Is set!" && break ; done' -- bar fooбудет работать.
Звездный день
2
Этот ответ был неправильным в течение последних четырех лет, потому что редактирование h7r сломало его. Оригинальный ответ (который я сейчас восстановил) работает при условии, что «ваша строка» не содержит символов глобуса и содержит несколько ложных срабатываний. Например, если команда create a new certificateи «ваша строка» cat, это сообщит о совпадении, поскольку certificate содержит cat .
Скотт
8

Как насчет поиска (с подстановочными знаками) всего пространства параметров:

if [[ $@ == *'-disableVenusBld'* ]]
then

Изменить: Хорошо, хорошо, так что это не был популярный ответ. Как насчет этого, это прекрасно!

if [[ "${@#-disableVenusBld}" = "$@" ]]
then
    echo "Did not find disableVenusBld"
else
    echo "Found disableVenusBld"
fi

Edit2: Хорошо, хорошо, возможно, это не идеально ... Думаю, что это работает, только если -param находится в начале списка и также будет соответствовать -paramXZY или -paramABC. Я все еще думаю, что оригинальная проблема может быть решена очень хорошо с манипулированием строк bash, но я не совсем взломал это здесь ... -Можете?

Богатый
источник
Ваше второе предложение - сравнение фильтрующей подстановки с полной подстановкой - работает достаточно хорошо и имеет то преимущество, что не нарушает список аргументов.
Donal Fellows
Не могли бы вы объяснить, что делает второе предложение (особенно ${@#)?
ворачивается
1
@velop Конечно! Итак, вы знаете, что $@это специальная переменная, которая содержит все аргументы командной строки? Ну, я только что использовал манипуляции строк Bash для этой переменной, чтобы удалить подстроку «-disableVenusBld», а затем сравнил ее с оригиналом $@. Так что, если $@равен, -foo -barто ${@#-disableVenusBld}все равно будет -foo -bar, так что я вижу, что флаг, который я ищу, отсутствует. Однако, если $@равно, -foo -disableVenusBld -barто ${@#-disableVenusBld}было бы, -foo -barчто не равно $@, таким образом говоря мне, что флаг, который я ищу, присутствует! Круто ах!
Богатое
@velop Узнайте больше о манипулировании строками Bash здесь: tldp.org/LDP/abs/html/string-manipulation.html
Rich
@ Рич довольно красиво ^^, спасибо за объяснение.
ворачивается
4
disCopperBld=
for x; do
  if [ "$x" = "-disCopperBld" ]; then disCopperBld=1; break; fi
done
if [ -n "$disCopperBld" ]; then
  ...
fi

Если вам нужно проверить только параметры, начиная с $3, выполните поиск в функции:

## Usage: search_trailing_parameters NEEDLE NUM "$@"
## Search NEEDLE amongst the parameters, skipping $1 through ${$NUM}.
search_trailing_parameters () {
  needle=$1
  shift $(($2 + 2))
  for x; do
    if [ "$x" = "$needle" ]; then return 0; fi
  done
  return 1
}
if search_trailing_parameters -disCopperBld 2 "$@"; then
  ...
fi

Но мне интересно, почему вы пытаетесь сделать это в первую очередь, это не является общей необходимостью. Обычно вы обрабатываете варианты по порядку, как в ответе Денниса на предыдущий вопрос .

Жиль "ТАК - перестань быть злым"
источник