Sprawdź, czy którykolwiek z parametrów skryptu bash jest zgodny z ciągiem

67

Próbuję napisać skrypt, w którym chcę sprawdzić, czy którykolwiek z parametrów przekazanych do skryptu bash jest zgodny z ciągiem. Mam teraz konfigurację

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

ale może istnieć duża liczba parametrów, więc zastanawiałem się, czy istnieje lepszy sposób, aby to zrobić?

Dzięki

EDYCJA: Wypróbowałem ten fragment kodu i wywołałem skrypt z opcją -disableVenusBld, ale nadal wypisuje „Uruchamianie kompilacji”. czy robię coś źle? Z góry dziękuję!

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
źródło
Dzięki za odpowiedzi, doceniam, że poświęcasz mi czas na pomoc. Próbowałem kawałka kodu, ale nie mogę zrozumieć, co się dzieje. Jakieś pomysły? (
Wkleiłem
Hmm: to działa dla mnie. Dodałem #! /bin/sh -na górę tego, co tam umieściłeś, spowodowałem, że skrypt jest wykonywalny, a następnie ./t.shwypisuje „Uruchamianie kompilacji”, ale ./t.sh -disableVenusBldnic nie drukuje.
Norman Gray,

Odpowiedzi:

59

Wygląda na to, że wykonujesz obsługę opcji w skrypcie powłoki. Oto idiom tego:

#! /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

(Istnieje kilka konwencji dotyczących wcięcia ;;, a niektóre powłoki umożliwiają podanie opcji as (--opt1), aby pomóc w dopasowywaniu nawiasów, ale jest to podstawowy pomysł)

Norman Gray
źródło
3
shiftOświadczenie jest używany, gdy liczba argumentów do polecenia nie jest znana z góry, na przykład, gdy użytkownicy mogą dać jak najwięcej argumentów, jak im się podoba. W takich przypadkach argumenty są przetwarzane w whilepętli z warunkiem testu wynoszącym $#. Ten warunek jest spełniony, o ile liczba argumentów jest większa od zera. $1Zmienna i shiftproces oświadczenie każdy argument. Liczba argumentów jest zmniejszana za każdym razem, gdy shiftjest wykonywana, i ostatecznie staje się zerowa, po czym whilepętla wychodzi. źródło
Serge Stroobandt
Oto podobny przykład z dodatkowym echo $1 | sedprzetwarzaniem wartości argumentów .
Serge Stroobandt
26

To zadziałało dla mnie. Robi dokładnie to, o co prosiłeś i nic więcej (bez przetwarzania opcji). Czy to dobrze, czy źle to ćwiczenie na plakat :)

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

Wykorzystuje to specjalną obsługę $* suportów… i super-test [[]]wsporników.

Rich Homolka
źródło
2
IMHO to musiała być najbardziej poprawna odpowiedź, ponieważ pytanie wymaga jedynie sprawdzenia obecności parametru. Zmieniłem jednak, zmieniając $*na $@, ponieważ testowany ciąg może zawierać spacje i dodać link do dokumentacji bash na ten temat.
h7r
9
Czy chciałeś użyć operatora = ~? W przeciwnym razie nie rozumiem, dlaczego to powinno działać, i rzeczywiście nie działa, gdy wypróbuję dokładny skrypt.
Seppo Enarvi
3
Nie działa. bash -c 'echo args=$*; [[ "$@" == "bar" ]] && echo YES || echo NO' -- foo bar
Tobia,
2
Porównuje to całą listę argumentów your string. Myślę, że musisz zrobić to, co sugeruje ta odpowiedź . tj .: bash -c 'echo args=$*; for i in "$@" ; do [[ $i == "bar" ]] && echo "Is set!" && break ; done' -- bar foodziałałoby.
starfry
2
Ta odpowiedź była błędna przez ostatnie cztery lata, ponieważ edycja h7r ją zepsuła. Oryginalna odpowiedź (którą teraz przywróciłem) działa, pod warunkiem, że „Twój ciąg” nie zawiera znaków globu i zawiera pewne fałszywe alarmy. Na przykład, jeśli polecenie brzmi create a new certificate„Twój ciąg” cat, to zgłosi dopasowanie, ponieważ certificate zawiera cat .
Scott
8

Co powiesz na przeszukiwanie (za pomocą symboli wieloznacznych) całej przestrzeni parametrów:

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

Edycja: Ok, ok, więc to nie była popularna odpowiedź. Co powiesz na ten, jest idealny !:

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

Edycja2: Ok, ok, może to nie jest idealne ... Pomyśl, że to działa tylko wtedy, gdy -param jest na początku listy i będzie pasować do -paramXZY lub -paramABC. Nadal uważam, że oryginalny problem można bardzo ładnie rozwiązać za pomocą manipulacji ciągiem bash, ale nie całkiem go tutaj złamałem ... -Czy możesz?

Bogaty
źródło
Druga sugestia - porównanie podstawienia filtrującego z pełnym podstawieniem - działa dość dobrze i ma tę zaletę, że nie zakłóca listy argumentów.
Donal Fellows
Czy możesz wyjaśnić, co robi druga sugestia (szczególnie ${@#)?
velop
1
@velop Sure! Więc wiesz, że $@jest to specjalna zmienna, która przechowuje wszystkie argumenty wiersza poleceń? Właśnie użyłem manipulacji ciągiem Bash na tej zmiennej, aby usunąć podciąg „-disableVenusBld”, a następnie porównuję go do oryginału $@. Więc jeśli $@równa się, -foo -barto ${@#-disableVenusBld}nadal byłbym -foo -bar, więc widzę, że flaga, której szukam, nie jest obecna. Jeśli jednak $@jest równy, -foo -disableVenusBld -barto ${@#-disableVenusBld}nie byłby -foo -barrówny $@, mówiąc mi, że flaga, której szukam, jest obecna! Cool eh!
Bogaty
@velop Dowiedz się więcej o manipulacji ciągiem Bash tutaj: tldp.org/LDP/abs/html/string-manipulation.html
Rich
@Rich dość schludny ^^, dzięki za wyjaśnienie.
velop
4
disCopperBld=
for x; do
  if [ "$x" = "-disCopperBld" ]; then disCopperBld=1; break; fi
done
if [ -n "$disCopperBld" ]; then
  ...
fi

Jeśli chcesz przetestować tylko parametry zaczynające się od $3, wykonaj wyszukiwanie w funkcji:

## 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

Ale zastanawiam się, dlaczego starasz się to zrobić, to nie jest powszechna potrzeba. Zazwyczaj opcje są przetwarzane w kolejności, jak w odpowiedzi Dennisa na poprzednie pytanie .

Gilles „SO- przestań być zły”
źródło