Jag letar efter en konstruktion i bash
, för att bestämma om en variabel $WORD
är en av definierade ord. Jag behöver något så här:
if "$WORD" in dog cat horse ; then echo yes else echo no fi
har bash en sådan konstruktion? Om inte, vad skulle vara närmast?
Svar
Detta är en Bash-only-lösning (> = version 3) som använder reguljära uttryck:
if [[ "$WORD" =~ ^(cat|dog|horse)$ ]]; then echo "$WORD is in the list" else echo "$WORD is not in the list" fi
Om din ordlista är lång kan du spara den i en fil (ett ord per rad) och göra detta:
if [[ "$WORD" =~ $(echo ^\($(paste -sd"|" /your/file)\)$) ]]; then echo "$WORD is in the list" else echo "$WORD is not in the list" fi
En varning med filinriktningen:
-
Den kommer att brytas om filen har ett tomt utrymme. Detta kan åtgärdas med något som:
sed "s/[[:blank:]]//g" /your/file | paste -sd "|" /dev/stdin
Tack till @terdon för att jag påminde mig om att förankra mönstret ordentligt med ^
och $
.
Kommentarer
Svar
case $word in dog|cat|horse) echo yes;; *) echo no;; esac
Svar
Vad sägs om:
#!/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"
Sedan:
$ 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
- Var försiktig, men detta kommer att bli sant om
$WORD
är tom, men det matchar omWORD=ca
ellerWORD=og
eller liknande och jag antar att du menadeecho ${set[@]}
. - lägg bara till -w till grep för att undvika partiella ord
Svar
Du kan definiera en bash-funktion för detta:
function word_valid() { if [ "$1" != "cat" -a "$1" != "dog" -a "$1" != "horse" ];then echo no else echo yes fi }
Använd sedan helt enkelt så här:
word_valid cat
Svar
jag letade efter en ”en rad” -lösning för att validera mitt skriptargument och använde Joseph R. svar ovan för att komma upp med:
[[ "$ARG" =~ ^(true|false)$ ]] || { echo "Argument received invalid value" ; exit 1 ; }
Svar
Du kan använda fgrep för att ange alla tillåtna ord:
if $(echo "$WORD" | fgrep -wq -e dog -e cat -e horse) ; then echo yes else echo no fi
-w
-flaggan matchar endast fullständiga ord, -q
-flaggan gör att den fungerar tyst (eftersom allt vi behöver är returvärdet för if-uttalandet att använda), och varje -e
-mönster anger ett mönster att tillåta.
fgrep
är den version av grep som gör normal strängmatchning istället för regex-matchning. Om du har grep
bör du ha fgrep
, men om inte, är det identiskt med att använda grep
med -F
-flaggan (så skulle du bara ersätta fgrep -wq
ovan med grep -Fwq
).
Svar
Detta fungerade för 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
Du kanske vill lägga ordlistan i en fil, om du ändrar listan ofta eller vill att den ska delas av flera skript. Och du kan behöva lägga in orden i en fil om listan blir för lång för att hantera i ett skript. Då kan du säga
if fgrep –qx "$WORD" word_list
Kommentarer
- nej, jag vill inte ’ jag vill inte ha min lista i en fil
Svar
Om ord är en lista där värden är åtskilda av en ny rad kan du göra:
WORDS="$(ls -1)" if echo "${WORDS}" | grep --quiet --line-regexp --fixed-strings "${WORD}"; then echo yes else echo no fi
Svar
Jag hade precis samma problem och hittade en förvånansvärt förståelig lösning som inte kräver någon regex-kunskap.
Observera att Lösningen som visas nedan kan bara vara bash, för jag har ingen aning om skillnaderna mellan bash och andra skal. Dessutom varnar bash-handboken om att denna typ av mönstermatchning är långsam om strängen som ska matchas är lång.
WORD=abc [[ "$WORD" == @(def|abc|ghi|foo|barbaz) ]] && echo Word is in set.
Hur fungerar det?Jag vill inte upprepa stora delar av bash-manualen här, men med mina egna ord:
Om den binära operatören ==
används med sammansatt kommando [[
, ordet till höger om operatören genomgår mönstermatchning som förklaras i avsnittet ” Mönstermatchning ” i bash-handboken. Vidare antas att under dessa förhållanden, medan matchning, skalalternativet extglob
är inställt (oavsett den faktiska inställningen); detta är nyckelpunkten för att förstå ovanstående.
Men tänk om orden i din uppsättning redan innehåller tecken som har en speciell betydelse för mönstermatchning, kommandosättning och andra utvidgningar? Åtgärden är enkel: Använd bara något som
[[ "$WORD" == @("a*"|abc|"?ghi"|"$DontExpandMe"|barbaz) ]] && echo Word is in set.
Jag tyckte att det här var väldigt enkelt, förståeligt och effektivt (så länge som $WORD
är kort) lösning som inte har biverkningar eller är da som de set
-baserade metoderna.
shopt -s nocasematch
kan hjälpa om du vill att sökningen ska vara skiftlägeskänslig.[[
och]]
–[
och]
räcker inte.[[ "$ARG" =~ ^(true|false)$ ]] || { echo "Argument received invalid value" ; exit 1 ; }
egrep -q "^$WORD$" /tmp/words; [[ $? != 0 ]] && echo "Not found" || echo "OK"
.