Jeg leder efter en konstruktion i bash
, for at beslutte om en variabel $WORD
er et af definerede ord. Jeg har brug for noget som dette:
if "$WORD" in dog cat horse ; then echo yes else echo no fi
har bash sådan konstruktion? Hvis ikke, hvad ville være tættest?
Svar
Dette er en løsning, der kun er Bash (> = version 3), der bruger regulære udtryk:
if [[ "$WORD" =~ ^(cat|dog|horse)$ ]]; then echo "$WORD is in the list" else echo "$WORD is not in the list" fi
Hvis din ordliste er lang, kan du gemme den i en fil (et ord pr. linje) og gø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 filtilgangen:
-
Den går i stykker, hvis filen har et hvidt mellemrum. Dette kan afhjælpes med noget som:
sed "s/[[:blank:]]//g" /your/file | paste -sd "|" /dev/stdin
Tak til @terdon for at minde mig om at forankre mønsteret korrekt med ^
og $
.
Kommentarer
Svar
case $word in dog|cat|horse) echo yes;; *) echo no;; esac
Svar
Hvad 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"
Derefter:
$ 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
- Forsigtig, men dette vil returnere sandt, hvis
$WORD
er tom, det vil matche, hvisWORD=ca
ellerWORD=og
eller lignende, og jeg antager, at du menteecho ${set[@]}
. - bare tilføj -w til grep for at undgå delvise ord
Svar
Du kan definere en bash-funktion til dette:
function word_valid() { if [ "$1" != "cat" -a "$1" != "dog" -a "$1" != "horse" ];then echo no else echo yes fi }
Brug derefter simpelthen sådan:
word_valid cat
Svar
jeg søgte efter en “en linje” -løsning til at validere mit scriptargument og brugte Joseph R. svar ovenfor for at komme op med:
[[ "$ARG" =~ ^(true|false)$ ]] || { echo "Argument received invalid value" ; exit 1 ; }
Svar
Dig kunne bruge fgrep til at specificere alle tilladte ord:
if $(echo "$WORD" | fgrep -wq -e dog -e cat -e horse) ; then echo yes else echo no fi
-w
flag matcher kun fulde ord, -q
flag får det til at fungere lydløst (fordi alt, hvad vi har brug for, er returværdien for if-sætningen, der skal bruges), og hvert -e
-mønster angiver et mønster at tillade.
fgrep
er den version af grep, der udfører normal strengtilpasning i stedet for regex-matching. Hvis du har grep
, skal du have fgrep
, men hvis ikke, er det identisk med at bruge grep
med -F
flag (så du bare erstatter fgrep -wq
ovenfor med grep -Fwq
).
Svar
Dette fungerede for mig:
#!/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 en god idé at placere ordlisten i en fil, hvis du ændrer listen ofte, eller hvis du vil have den til deles af flere scripts. Og det kan være nødvendigt at du sætter ordene i en fil, hvis listen bliver for lang til at administrere i et script. Derefter kan du sige
if fgrep –qx "$WORD" word_list
Kommentarer
- nej, jeg vil ikke ‘ Jeg vil ikke have min liste i en fil
Svar
Hvis ord er en liste, hvor værdier er adskilt af en ny linje, kan du gøre:
WORDS="$(ls -1)" if echo "${WORDS}" | grep --quiet --line-regexp --fixed-strings "${WORD}"; then echo yes else echo no fi
Svar
Jeg havde lige det samme problem og fandt en overraskende forståelig løsning, der ikke kræver nogen regex-viden.
Vær opmærksom på, at løsningen vist nedenfor er muligvis kun bash, fordi jeg ikke har nogen anelse om forskellene mellem bash og andre skaller. Desuden advarer bashmanualen om, at denne form for mønstermatchning er langsom, hvis den streng, der skal matches, er lang.
WORD=abc [[ "$WORD" == @(def|abc|ghi|foo|barbaz) ]] && echo Word is in set.
Hvordan fungerer dette?Jeg vil ikke gentage store dele af bash-manualen her, men med mine egne ord:
Hvis den binære operator ==
bruges sammen med kommandoen sammensat [[
, ordet til højre for operatøren gennemgår mønstermatchning som forklaret i sektionen ” Mønster matchende ” i bash-manualen. Desuden antages det under disse forhold, mens matchning, skalindstillingen extglob
at være indstillet (uanset den aktuelle indstilling); dette er nøglepunktet i forståelsen af ovenstående.
Men hvad nu hvis ordene i dit sæt allerede indeholder tegn, der har en særlig betydning i mønstermatchning, kommandosubstitution og andre udvidelser? Løsningen er let: Brug bare noget som
[[ "$WORD" == @("a*"|abc|"?ghi"|"$DontExpandMe"|barbaz) ]] && echo Word is in set.
Jeg fandt dette meget let, forståeligt og effektivt (så længe $WORD
er kort) opløsning, der ikke har bivirkninger eller er da svær som de set
-baserede metoder.
shopt -s nocasematch
kan hjælpe, hvis du vil have, at søgningen ikke skelnes mellem store og små bogstaver.[[
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"
.