bash: testați dacă $ WORD este în set

Caut un construct în bash, pentru a decide dacă o variabilă $WORD este unul dintre cuvintele definite. Am nevoie de așa ceva:

if "$WORD" in dog cat horse ; then echo yes else echo no fi 

are bash o astfel de construcție? Dacă nu, care ar fi cea mai apropiată?

Răspuns

Aceasta este o soluție Bash-only (> = versiunea 3) care folosește expresii regulate:

if [[ "$WORD" =~ ^(cat|dog|horse)$ ]]; then echo "$WORD is in the list" else echo "$WORD is not in the list" fi 

Dacă lista de cuvinte este lungă, o puteți stoca într-un fișier (un cuvânt pe rând) și faceți acest lucru:

if [[ "$WORD" =~ $(echo ^\($(paste -sd"|" /your/file)\)$) ]]; then echo "$WORD is in the list" else echo "$WORD is not in the list" fi 

Un avertisment cu abordarea fișierului:

  • Se va întrerupe dacă fișierul are spațiu alb. Acest lucru poate fi remediat prin ceva de genul:

    sed "s/[[:blank:]]//g" /your/file | paste -sd "|" /dev/stdin 

Mulțumesc lui @terdon că mi-a reamintit să ancorez corect modelul cu ^ și $.

Comentarii

  • Și shopt -s nocasematch vă poate ajuta dacă doriți căutarea să nu distingă majuscule și minuscule.
  • Rețineți că trebuie să utilizați [[ și ]][ și ] nu sunt suficiente.
  • căutam pentru ca un ‘ oneliner ‘ să valideze argumentul meu script și acest lucru a funcționat perfect. mulțumesc! [[ "$ARG" =~ ^(true|false)$ ]] || { echo "Argument received invalid value" ; exit 1 ; }
  • Dacă ‘ doriți să introduceți lista de potriviri într-un fișier, ați putea folosi la fel de bine grep: egrep -q "^$WORD$" /tmp/words; [[ $? != 0 ]] && echo "Not found" || echo "OK".

Răspuns

case $word in dog|cat|horse) echo yes;; *) echo no;; esac 

Răspuns

Ce zici de:

#!/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" 

Apoi:

$ a.sh cat cat is in the list $ a.sh bob bob is not in the list 

Răspuns

if (echo "$set" | fgrep -q "$WORD") 

Comentarii

  • Cu toate acestea, cu atenție, acest lucru va reveni adevărat dacă $WORD este gol, se va potrivi dacă WORD=ca sau WORD=og sau similar și presupun că ai vrut să spui echo ${set[@]}.
  • adaugă -w la grep pentru a evita cuvintele parțiale

Răspuns

Puteți defini o funcție bash pentru aceasta:

function word_valid() { if [ "$1" != "cat" -a "$1" != "dog" -a "$1" != "horse" ];then echo no else echo yes fi } 

Apoi utilizați pur și simplu așa:

word_valid cat 

Răspuns

Căutam o soluție „cu o singură linie” pentru a valida argumentul meu de script și am folosit Joseph R. answer mai sus pentru a veni cu:

[[ "$ARG" =~ ^(true|false)$ ]] || { echo "Argument received invalid value" ; exit 1 ; }

Răspuns

Tu ar putea folosi fgrep pentru a specifica toate cuvintele permise:

if $(echo "$WORD" | fgrep -wq -e dog -e cat -e horse) ; then echo yes else echo no fi 

Steagul -w se potrivește numai cu cuvinte complete, -q îl face să funcționeze silențios (pentru că tot ce avem nevoie este valoarea returnată pentru instrucțiunea if de utilizat) și fiecare model -e specifică un model a permite.

fgrep este versiunea grep care face potrivire normală de șiruri în loc de potrivire regex. Dacă aveți grep, ar trebui să aveți fgrep, dar dacă nu, este identic cu utilizarea grep cu steagul -F (deci ați înlocui doar fgrep -wq de mai sus cu grep -Fwq).

Răspuns

Acest lucru a funcționat pentru mine:

#!/bin/bash phrase=(cat dog parrot cow horse) findthis=parrot for item in ${phrase[*]} do test "$item" == "$findthis" && { echo "$findthis found!"; break; } done 

Răspuns

Poate doriți să introduceți lista de cuvinte într-un fișier, în cazul în care modificați lista des sau doriți să să fie partajat de mai multe scripturi. Și poate fi necesar să introduceți cuvintele într-un fișier dacă lista devine prea lungă pentru a fi gestionată într-un script. Apoi puteți spune

if fgrep –qx "$WORD" word_list 

Comentarii

  • nu, nu ‘ nu vreau să am lista mea într-un fișier

Răspuns

Dacă cuvintele sunt o listă în care valorile sunt separate printr-o linie nouă, puteți face:

WORDS="$(ls -1)" if echo "${WORDS}" | grep --quiet --line-regexp --fixed-strings "${WORD}"; then echo yes else echo no fi 

Răspuns

Tocmai am avut aceeași problemă și am găsit o soluție surprinzător de înțeleasă, care nu necesită cunoștințe regex.

Vă rugăm să rețineți că soluția prezentată mai jos ar putea fi doar bash, deoarece nu am nici o idee despre diferențele dintre bash și alte cochilii. Mai mult, manualul bash avertizează că acest tip de potrivire a modelelor este lent dacă șirul care ar trebui să fie asortat este lung.

WORD=abc [[ "$WORD" == @(def|abc|ghi|foo|barbaz) ]] && echo Word is in set. 

Cum funcționează acest lucru?Nu vreau să repet porțiuni mari din manualul bash aici, dar în propriile mele cuvinte:

Dacă operatorul binar == este utilizat cu comanda compusă [[, cuvântul din partea dreaptă a operatorului suferă potrivirea modelelor, așa cum se explică în secțiunea ” Potrivirea modelelor ” în manualul bash. În plus, în aceste condiții, în timp ce se potrivește, se presupune că opțiunea shell extglob este setată (indiferent de setarea reală); aceasta este punctul cheie în înțelegerea celor de mai sus.

Dar ce se întâmplă dacă cuvintele din setul dvs. conțin deja caractere care au o semnificație specială în potrivirea modelelor, înlocuirea comenzilor și alte expansiuni? Remediul este ușor: folosiți doar ceva de genul

[[ "$WORD" == @("a*"|abc|"?ghi"|"$DontExpandMe"|barbaz) ]] && echo Word is in set. 

Mi s-a părut foarte ușor, ușor de înțeles și eficient (atâta timp cât $WORD este scurt) soluție care nu are efecte secundare sau este da ciudat ca metodele bazate pe set.

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *