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
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śliWORD=ca
lubWORD=og
lub podobne i zakładam, że miałeś na myśliecho ${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
.
shopt -s nocasematch
może pomóc, jeśli chcesz, aby wyszukiwanie nie uwzględniało wielkości liter.[[
i]]
–[
i]
to za mało.[[ "$ARG" =~ ^(true|false)$ ]] || { echo "Argument received invalid value" ; exit 1 ; }
egrep -q "^$WORD$" /tmp/words; [[ $? != 0 ]] && echo "Not found" || echo "OK"
.