bash: sprawdź, czy $ WORD jest w zestawie

Szukam konstrukcji w bash, aby zdecydować, czy zmienna $WORD jest jednym ze zdefiniowanych słów. Potrzebuję czegoś takiego:

if "$WORD" in dog cat horse ; then echo yes else echo no fi 

Czy bash ma taką konstrukcję? Jeśli nie, jakie byłoby najbliższe rozwiązanie?

Odpowiedź

To jest tylko rozwiązanie Bash (> = wersja 3), które używa wyrażeń regularnych:

if [[ "$WORD" =~ ^(cat|dog|horse)$ ]]; then echo "$WORD is in the list" else echo "$WORD is not in the list" fi 

Jeśli twoja lista słów jest długa, możesz zapisać ją w pliku (jedno słowo w linii) i zrobić to:

if [[ "$WORD" =~ $(echo ^\($(paste -sd"|" /your/file)\)$) ]]; then echo "$WORD is in the list" else echo "$WORD is not in the list" fi 

Jedno zastrzeżenie dotyczące podejścia do pliku:

  • Zepsuje się, jeśli plik ma białe znaki. Można temu zaradzić w następujący sposób:

    sed "s/[[:blank:]]//g" /your/file | paste -sd "|" /dev/stdin 

Dzięki @terdon za przypomnienie mi o prawidłowym zakotwiczeniu wzorca za pomocą ^ i $.

Komentarze

  • I shopt -s nocasematch może pomóc, jeśli chcesz, aby wyszukiwanie nie uwzględniało wielkości liter.
  • Pamiętaj, że musisz użyć [[ i ]][ i ] to za mało.
  • szukałem dla ' onelinera ' w celu sprawdzenia poprawności mojego argumentu skryptu. Dziękuję Ci! [[ "$ARG" =~ ^(true|false)$ ]] || { echo "Argument received invalid value" ; exit 1 ; }
  • Jeśli ' zamierzasz umieścić listę dopasowań w pliku, równie dobrze możesz użyć grep: egrep -q "^$WORD$" /tmp/words; [[ $? != 0 ]] && echo "Not found" || echo "OK".

Odpowiedź

case $word in dog|cat|horse) echo yes;; *) echo no;; esac 

Odpowiedź

Co powiesz na:

#!/usr/bin/env bash WORD="$1" for w in dog cat horse do if [ "$w" == "$WORD" ] then yes=1 break fi done; [ "$yes" == "1" ] && echo "$WORD is in the list" || echo "$WORD is not in the list" 

Następnie:

$ a.sh cat cat is in the list $ a.sh bob bob is not in the list 

Odpowiedź

if (echo "$set" | fgrep -q "$WORD") 

Komentarze

  • Ostrożnie, to zwróci prawdę, jeśli $WORD jest pusty, będzie pasował, jeśli WORD=ca lub WORD=og lub podobne i zakładam, że miałeś na myśli echo ${set[@]}.
  • po prostu dodaj -w do grep, aby uniknąć częściowych słów

Odpowiedź

W tym celu można zdefiniować funkcję bash:

function word_valid() { if [ "$1" != "cat" -a "$1" != "dog" -a "$1" != "horse" ];then echo no else echo yes fi } 

Następnie użyj po prostu w ten sposób:

word_valid cat 

Odpowiedź

szukałem rozwiązania „jednej linii”, aby sprawdzić poprawność argumentu skryptu, i użyłem odpowiedzi Josepha R. powyżej. się z:

[[ "$ARG" =~ ^(true|false)$ ]] || { echo "Argument received invalid value" ; exit 1 ; }

Odpowiedź

Ty może użyć fgrep do określenia wszystkich dozwolonych słów:

if $(echo "$WORD" | fgrep -wq -e dog -e cat -e horse) ; then echo yes else echo no fi 

Flaga -w pasuje tylko do pełnych słów, -q sprawia, że działa ona cicho (ponieważ potrzebujemy tylko wartości zwracanej instrukcji if), a każdy wzorzec -e określa wzorzec aby zezwolić.

fgrep to wersja grep, która wykonuje normalne dopasowywanie ciągów znaków zamiast dopasowywania wyrażeń regularnych. Jeśli masz grep, powinieneś mieć fgrep, ale jeśli nie, jest to identyczne z użyciem grep z flagą -F (więc wystarczy zamienić fgrep -wq powyżej na grep -Fwq).

Odpowiedź

U mnie to zadziałało:

#!/bin/bash phrase=(cat dog parrot cow horse) findthis=parrot for item in ${phrase[*]} do test "$item" == "$findthis" && { echo "$findthis found!"; break; } done 

Odpowiedź

Możesz zechcieć umieścić listę słów w pliku, na wypadek gdybyś często zmieniał listę lub chcesz być współużytkowane przez wiele skryptów. Może być konieczne umieszczenie słów w pliku, jeśli lista stanie się zbyt długa, aby można było nią zarządzać w skrypcie. Następnie możesz powiedzieć

if fgrep –qx "$WORD" word_list 

Komentarze

  • nie, nie ' nie chcę mieć mojej listy w pliku

Odpowiedź

Jeśli słowa są listą, na której wartości są oddzielone znakiem nowej linii, możesz:

WORDS="$(ls -1)" if echo "${WORDS}" | grep --quiet --line-regexp --fixed-strings "${WORD}"; then echo yes else echo no fi 

Odpowiedź

Właśnie miałem ten sam problem i znalazłem zaskakująco zrozumiałe rozwiązanie, które nie wymaga znajomości wyrażeń regularnych.

Zwróć uwagę, że Rozwiązanie pokazane poniżej może być tylko bashem, ponieważ nie mam pojęcia o różnicach między bashem a innymi powłokami. Ponadto podręcznik basha ostrzega, że ten rodzaj dopasowywania wzorców jest powolny, jeśli ciąg, który ma być dopasowany, jest długi.

WORD=abc [[ "$WORD" == @(def|abc|ghi|foo|barbaz) ]] && echo Word is in set. 

Jak to działa?Nie chcę tutaj powtarzać dużych fragmentów instrukcji basha, ale własnymi słowami:

Jeśli operator binarny == jest używany z poleceniem złożonym [[, słowo po prawej stronie operatora podlega dopasowaniu do wzorca, jak wyjaśniono w sekcji ” Dopasowanie do wzorca ” w podręczniku basha. Ponadto, w tych warunkach, podczas dopasowywania, zakłada się, że opcja powłoki extglob jest ustawiona (niezależnie od rzeczywistego ustawienia); jest to kluczowy punkt w zrozumieniu powyższego.

Ale co, jeśli słowa w twoim zestawie zawierają już znaki, które mają specjalne znaczenie w dopasowywaniu wzorców, podstawianiu poleceń i innych rozszerzeniach? Rozwiązanie jest proste: po prostu użyj czegoś takiego jak

[[ "$WORD" == @("a*"|abc|"?ghi"|"$DontExpandMe"|barbaz) ]] && echo Word is in set. 

Uważam, że jest to bardzo łatwe, zrozumiałe i wydajne (o ile $WORD jest krótkie) rozwiązanie, które nie ma skutków ubocznych lub jest da ngerous jak metody oparte na set.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *