Jeg leter etter en konstruksjon i bash
, for å bestemme om en variabel $WORD
er en av definerte ord. Jeg trenger noe sånt:
if "$WORD" in dog cat horse ; then echo yes else echo no fi
har bash en slik konstruksjon? Hvis ikke, hva ville være nærmest?
Svar
Dette er en Bash-only-løsning (> = versjon 3) som bruker vanlige uttrykk:
if [[ "$WORD" =~ ^(cat|dog|horse)$ ]]; then echo "$WORD is in the list" else echo "$WORD is not in the list" fi
Hvis ordlisten din er lang, kan du lagre den i en fil (ett ord per linje) og gjøre dette:
if [[ "$WORD" =~ $(echo ^\($(paste -sd"|" /your/file)\)$) ]]; then echo "$WORD is in the list" else echo "$WORD is not in the list" fi
Én advarsel med filtilnærmingen:
-
Den vil brytes hvis filen har et mellomrom. Dette kan avhjelpes med noe sånt som:
sed "s/[[:blank:]]//g" /your/file | paste -sd "|" /dev/stdin
Takk til @terdon som påminner meg om å forankre mønsteret riktig med ^
og $
.
Kommentarer
Svar
case $word in dog|cat|horse) echo yes;; *) echo no;; esac
Svar
Hva med:
#!/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"
Deretter:
$ a.sh cat cat is in the list $ a.sh bob bob is not in the list
Svar
if (echo "$set" | fgrep -q "$WORD")
Kommentarer
- Forsiktig, men dette vil være sant hvis
$WORD
er tom, det vil matche hvisWORD=ca
ellerWORD=og
eller lignende, og jeg antar at du menteecho ${set[@]}
. - bare legg til -w til grep for å unngå delvise ord
Svar
Du kan definere en bash-funksjon for dette:
function word_valid() { if [ "$1" != "cat" -a "$1" != "dog" -a "$1" != "horse" ];then echo no else echo yes fi }
Bruk så enkelt slik:
word_valid cat
Svar
jeg lette etter en «en linje» -løsning for å validere skriptargumentet mitt, og brukte Joseph R. svar ovenfor for å komme opp med:
[[ "$ARG" =~ ^(true|false)$ ]] || { echo "Argument received invalid value" ; exit 1 ; }
Svar
Du kunne bruke fgrep til å spesifisere alle tillatte ord:
if $(echo "$WORD" | fgrep -wq -e dog -e cat -e horse) ; then echo yes else echo no fi
-w
-flagget samsvarer bare med fulle ord, -q
-flagg gjør at det fungerer stille (fordi alt vi trenger er returverdien for if-setningen som skal brukes), og hvert -e
-mønster angir et mønster å tillate.
fgrep
er versjonen av grep som utfører normal strengtilpasning i stedet for samsvar med regex. Hvis du har grep
, bør du ha fgrep
, men hvis ikke, er det identisk med å bruke grep
med -F
-flagget (så du bare erstatter fgrep -wq
over med grep -Fwq
).
Svar
Dette fungerte for meg:
#!/bin/bash phrase=(cat dog parrot cow horse) findthis=parrot for item in ${phrase[*]} do test "$item" == "$findthis" && { echo "$findthis found!"; break; } done
Svar
Det kan være lurt å sette ordlisten i en fil, i tilfelle du endrer listen ofte, eller hvis du vil at den skal deles av flere skript. Og det kan hende du må legge ordene inn i en fil hvis listen blir for lang til å administreres i et skript. Så kan du si
if fgrep –qx "$WORD" word_list
Kommentarer
- nei, jeg vil ikke ‘ jeg vil ikke ha listen min i en fil
Svar
Hvis ord er en liste der verdiene er atskilt med en ny linje, kan du gjøre:
WORDS="$(ls -1)" if echo "${WORDS}" | grep --quiet --line-regexp --fixed-strings "${WORD}"; then echo yes else echo no fi
Svar
Jeg hadde akkurat det samme problemet og fant en overraskende forståelig løsning som ikke krever noen regex-kunnskap.
Vær oppmerksom på at løsningen vist nedenfor kan være bare bash, fordi jeg ikke har noen anelse om forskjellene mellom bash og andre skall. Videre advarer bashmanualen om at denne typen mønstermatching er treg hvis strengen som skal matches, er lang.
WORD=abc [[ "$WORD" == @(def|abc|ghi|foo|barbaz) ]] && echo Word is in set.
Hvordan fungerer dette?Jeg vil ikke gjenta store deler av bash-manualen her, men med mine egne ord:
Hvis den binære operatoren ==
brukes med sammensatt kommando [[
, ordet til høyre for operatøren gjennomgår mønstermatching som forklart i seksjonen » Mønstermatching » i bash-håndboken. Videre antas det at under disse forholdene, mens matching, skalalternativet extglob
er satt (uavhengig av den faktiske innstillingen); dette er nøkkelpunktet i å forstå det ovennevnte.
Men hva om ordene i settet ditt allerede inneholder tegn som har en spesiell betydning i mønstermatching, kommandosubstitusjon og andre utvidelser? Løsningen er enkel: Bare bruk noe sånt som
[[ "$WORD" == @("a*"|abc|"?ghi"|"$DontExpandMe"|barbaz) ]] && echo Word is in set.
Jeg syntes dette var veldig enkelt, forståelig og effektivt (så lenge $WORD
er kort) løsning som ikke har bivirkninger eller er da ngerøs som set
-baserte metoder.
shopt -s nocasematch
kan hjelpe hvis du vil at søket ikke skal skiftes mellom store og små bokstaver.[[
og]]
–[
og]
er ikke nok.[[ "$ARG" =~ ^(true|false)$ ]] || { echo "Argument received invalid value" ; exit 1 ; }
egrep -q "^$WORD$" /tmp/words; [[ $? != 0 ]] && echo "Not found" || echo "OK"
.