bash: test om $ WORD er i sæt

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

  • Og shopt -s nocasematch kan hjælpe, hvis du vil have, at søgningen ikke skelnes mellem store og små bogstaver.
  • Bemærk, at du skal bruge [[ og ]][ og ] er ikke nok.
  • Jeg søgte for en ‘ oneliner ‘ for at validere mit scriptargument, og dette fungerede perfekt. tak skal du have! [[ "$ARG" =~ ^(true|false)$ ]] || { echo "Argument received invalid value" ; exit 1 ; }
  • Hvis du ‘ vil lægge din liste over matches i en fil, kan du lige så godt bruge grep: egrep -q "^$WORD$" /tmp/words; [[ $? != 0 ]] && echo "Not found" || echo "OK".

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, hvis WORD=ca eller WORD=og eller lignende, og jeg antager, at du mente echo ${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.

Skriv et svar

Din e-mailadresse vil ikke blive publiceret. Krævede felter er markeret med *