Перевірте, чи відповідає будь-який параметр bash-скрипту рядку


67

Я намагаюся написати сценарій, де я хочу перевірити, чи будь-який з параметрів, переданих bash-скрипту, відповідає рядку. Зараз у мене це налаштування

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

але може бути велика кількість параметрів, тому мені було цікаво, чи є кращий спосіб зробити це?

Дякую

EDIT: Я спробував цей фрагмент коду і назвав скрипт з опцією -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

Дякую за відповіді, хлопці, я вдячний, що ви потребуєте часу, щоб допомогти мені. Я спробував фрагмент коду, але не можу зрозуміти, що відбувається не так. Будь-які ідеї? (Я вставив код у
редакції

Хм: це працює для мене. Я додав #! /bin/sh -до початку того, що ви туди включили, зробив сценарій виконуваним, потім ./t.shнадрукує "Початок складання", але ./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цикл виходить. джерело
Serge Stroobandt

Ось подібний приклад з додатковою echo $1 | sedобробкою значення аргументу .
Серж Стротобанд

26

Це працювало для мене. Це робить саме те, про що ви просили, і більше нічого (без обробки варіантів). Це добре чи погано - це вправа для афіші :)

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

Це має перевагу спеціальної обробки $* і Баш супер-тест [[... ]]дужки.


2
ІМХО це мало бути найбільш правильною відповіддю, оскільки питання вимагає лише перевірити наявність параметра. Я редагував, однак, змінюється $*на $@, так щоб бути тестована рядок може містити пробіли і додав посилання на документацію BASh про це.
h7r

9
Ви мали на увазі використовувати оператор = ~? Інакше я не бачу, чому це має працювати, і справді це не працює, коли я спробую точний сценарій.
Seppo Enarvi

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працював би.
starfry

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. Я все ще думаю, що оригінальну проблему можна дуже красиво вирішити за допомогою маніпуляції з струнною стрілкою, але я не дуже зламав її тут ... -Можеш ??


Ваша друга пропозиція - порівнюючи заміну фільтрації з повною заміною - працює досить добре і має перевагу в тому, щоб не порушувати список аргументів.
Стипендіати Дональда

Чи можете ви пояснити, що робить друга пропозиція (особливо ${@#)?
велоп

1
@velop Звичайно! Отже, ви знаєте, що $@це спеціальна змінна, яка містить усі аргументи командного рядка? Ну щойно я використовував маніпуляцію з рядком Баша на цій змінній, щоб видалити підрядку "-disableVenusBld", а потім порівнюю її з оригіналом $@. Тож якщо $@дорівнюватиме, -foo -barто ${@#-disableVenusBld}все одно було б -foo -bar, тож я можу побачити, що прапора, якого я шукаю, немає. Однак, якщо $@одно , -foo -disableVenusBld -barто ${@#-disableVenusBld}буде -foo -bar, не дорівнює $@, що говорить мені , що прапор Я шукаю присутній! Класна е-е!
Багатий

@velop Дізнайтеся більше про Bash маніпуляцій зі рядками тут: tldp.org/LDP/abs/html/string-manipulation.html
Rich

@Rich досить акуратний ^^, THX для пояснення.
велоп

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

Але мені цікаво, чому ви намагаєтесь це зробити в першу чергу, це не є загальною потребою. Зазвичай ви обробляєте варіанти в порядку, як у відповіді Денніса на попереднє запитання .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.