bash: test om $ WORD er i sett

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

  • Og shopt -s nocasematch kan hjelpe hvis du vil at søket ikke skal skiftes mellom store og små bokstaver.
  • Merk at du må bruke [[ og ]][ og ] er ikke nok.
  • Jeg søkte for en ‘ oneliner ‘ for å validere skriptargumentet mitt, og dette fungerte perfekt. Takk skal du ha! [[ "$ARG" =~ ^(true|false)$ ]] || { echo "Argument received invalid value" ; exit 1 ; }
  • Hvis du ‘ skal legge listen over treff i en fil, kan du like godt bruke 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

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

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *