bash: testa om $ WORD är i set

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

  • Och shopt -s nocasematch kan hjälpa om du vill att sökningen ska vara skiftlägeskänslig.
  • Observera att du måste använda [[ och ]][ och ] räcker inte.
  • Jag sökte för en ’ oneliner ’ för att validera mitt skriptargument, och detta fungerade perfekt. tack! [[ "$ARG" =~ ^(true|false)$ ]] || { echo "Argument received invalid value" ; exit 1 ; }
  • Om du ’ ska lägga din lista över matchningar i en fil, kan du lika gärna använda 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

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 om WORD=ca eller WORD=og eller liknande och jag antar att du menade echo ${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.

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *