ik ben op zoek naar een construct in bash
, om te beslissen of een variabele $WORD
is een van de gedefinieerde woorden. Ik heb zoiets als dit nodig:
if "$WORD" in dog cat horse ; then echo yes else echo no fi
heeft bash zon constructie? Zo niet, wat zou het dichtst in de buurt komen?
Answer
Dit is een alleen Bash (> = versie 3) oplossing die gebruikt reguliere expressies:
if [[ "$WORD" =~ ^(cat|dog|horse)$ ]]; then echo "$WORD is in the list" else echo "$WORD is not in the list" fi
Als uw woordenlijst lang is, kunt u deze opslaan in een bestand (één woord per regel) en dit doen:
if [[ "$WORD" =~ $(echo ^\($(paste -sd"|" /your/file)\)$) ]]; then echo "$WORD is in the list" else echo "$WORD is not in the list" fi
Een voorbehoud bij de bestandsbenadering:
-
Het zal breken als het bestand witruimte heeft. Dit kan worden verholpen door zoiets als:
sed "s/[[:blank:]]//g" /your/file | paste -sd "|" /dev/stdin
Dank aan @terdon voor het eraan herinneren dat ik het patroon goed moet verankeren met ^
en $
.
Reacties
Antwoord
case $word in dog|cat|horse) echo yes;; *) echo no;; esac
Antwoord
Hoe zit het met:
#!/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"
Vervolgens:
$ a.sh cat cat is in the list $ a.sh bob bob is not in the list
Antwoord
if (echo "$set" | fgrep -q "$WORD")
Reacties
- Pas echter op, dit zal true retourneren als
$WORD
leeg is, het komt overeen alsWORD=ca
ofWORD=og
of iets dergelijks en ik neem aan dat jeecho ${set[@]}
bedoelde. - voeg gewoon toe -w naar grep om gedeeltelijke woorden te vermijden
Answer
Je zou hiervoor een bash-functie kunnen definiëren:
function word_valid() { if [ "$1" != "cat" -a "$1" != "dog" -a "$1" != "horse" ];then echo no else echo yes fi }
Gebruik dan gewoon zo:
word_valid cat
Antwoord
ik was op zoek naar een “één regel” -oplossing om mijn scriptargument te valideren, en gebruikte Joseph R. antwoord hierboven om te komen op met:
[[ "$ARG" =~ ^(true|false)$ ]] || { echo "Argument received invalid value" ; exit 1 ; }
Antwoord
Jij zou fgrep kunnen gebruiken om alle toegestane woorden te specificeren:
if $(echo "$WORD" | fgrep -wq -e dog -e cat -e horse) ; then echo yes else echo no fi
De -w
vlag komt alleen overeen met volledige woorden, de -q
vlag zorgt ervoor dat het stil werkt (omdat we alleen de retourwaarde nodig hebben om de if-instructie te gebruiken), en elk -e
patroon specificeert een patroon toe te staan.
fgrep
is de versie van grep die normale string-matching uitvoert in plaats van regex-matching. Als je grep
hebt, zou je fgrep
moeten hebben, maar zo niet, dan is het identiek aan het gebruik van grep
met de -F
vlag (dus je zou fgrep -wq
hierboven vervangen door grep -Fwq
).
Antwoord
Dit werkte voor mij:
#!/bin/bash phrase=(cat dog parrot cow horse) findthis=parrot for item in ${phrase[*]} do test "$item" == "$findthis" && { echo "$findthis found!"; break; } done
Antwoord
Misschien wilt u de lijst met woorden in een bestand plaatsen, voor het geval u de lijst vaak wijzigt, of u wilt dat worden gedeeld door meerdere scripts. En mogelijk moet u de woorden in een bestand plaatsen als de lijst te lang wordt om in een script te beheren. Dan kunt u zeggen:
if fgrep –qx "$WORD" word_list
Reacties
- nee, ik wil niet ‘ mijn lijst in een bestand hebben
Answer
Als woorden een lijst zijn waarin waarden worden gescheiden door een nieuwe regel, kunt u het volgende doen:
WORDS="$(ls -1)" if echo "${WORDS}" | grep --quiet --line-regexp --fixed-strings "${WORD}"; then echo yes else echo no fi
Answer
Ik had net hetzelfde probleem en vond een verrassend begrijpelijke oplossing waarvoor geen kennis van regex vereist is.
Houd er rekening mee dat de De onderstaande oplossing is mogelijk alleen bash, omdat ik geen idee heb van de verschillen tussen bash en andere shells. Verder waarschuwt de bash-handleiding dat dit soort patroonafstemming traag is als de string die moet worden aangepast lang is.
WORD=abc [[ "$WORD" == @(def|abc|ghi|foo|barbaz) ]] && echo Word is in set.
Hoe werkt dit?Ik wil hier geen grote delen van de bash-handleiding herhalen, maar in mijn eigen woorden:
Als de binaire operator ==
wordt gebruikt met het samengestelde commando [[
, het woord aan de rechterkant van de operator ondergaat patroonovereenkomst zoals uitgelegd in de sectie ” Patroonovereenkomst ” in de bash-handleiding. Verder wordt onder deze omstandigheden, tijdens het matchen, aangenomen dat de shell-optie extglob
is ingesteld (ongeacht de feitelijke instelling); dit is het belangrijkste punt om het bovenstaande te begrijpen.
Maar wat als de woorden in uw set al tekens bevatten die een speciale betekenis hebben bij het matchen van patronen, het vervangen van opdrachten en andere uitbreidingen? De oplossing is eenvoudig: gebruik gewoon zoiets als
[[ "$WORD" == @("a*"|abc|"?ghi"|"$DontExpandMe"|barbaz) ]] && echo Word is in set.
Ik vond dit een zeer gemakkelijke, begrijpelijke en efficiënte (zolang $WORD
kort is) oplossing die geen bijwerkingen heeft of da is kwaadaardig zoals de set
-gebaseerde methoden.
shopt -s nocasematch
kan helpen als u wilt dat de zoekopdracht niet hoofdlettergevoelig is.[[
en]]
–[
en]
zijn niet genoeg.[[ "$ARG" =~ ^(true|false)$ ]] || { echo "Argument received invalid value" ; exit 1 ; }
egrep -q "^$WORD$" /tmp/words; [[ $? != 0 ]] && echo "Not found" || echo "OK"
.