Sto cercando un costrutto in bash
, per decidere se una variabile $WORD
è una delle parole definite. Ho bisogno di qualcosa del genere:
if "$WORD" in dog cat horse ; then echo yes else echo no fi
bash ha un tale costrutto? In caso contrario, quale sarebbe la più vicina?
Risposta
Questa è una soluzione solo Bash (> = versione 3) che utilizza espressioni regolari:
if [[ "$WORD" =~ ^(cat|dog|horse)$ ]]; then echo "$WORD is in the list" else echo "$WORD is not in the list" fi
Se il tuo elenco di parole è lungo, puoi memorizzarlo in un file (una parola per riga) e fare così:
if [[ "$WORD" =~ $(echo ^\($(paste -sd"|" /your/file)\)$) ]]; then echo "$WORD is in the list" else echo "$WORD is not in the list" fi
Un avvertimento con lapproccio file:
-
Si interromperà se il file ha spazi bianchi. Questo può essere risolto con qualcosa del tipo:
sed "s/[[:blank:]]//g" /your/file | paste -sd "|" /dev/stdin
Grazie a @terdon per avermi ricordato di ancorare correttamente lo schema con ^
e $
.
Commenti
Risposta
case $word in dog|cat|horse) echo yes;; *) echo no;; esac
Risposta
Che ne dici di:
#!/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"
Quindi:
$ a.sh cat cat is in the list $ a.sh bob bob is not in the list
Rispondi
if (echo "$set" | fgrep -q "$WORD")
Commenti
- Attenzione però, questo restituirà true se
$WORD
è vuoto, corrisponderà seWORD=ca
oWORD=og
o simili e presumo che tu intendessiecho ${set[@]}
. - aggiungi semplicemente -w a grep per evitare parole parziali
Answer
Potresti definire una funzione bash per questo:
function word_valid() { if [ "$1" != "cat" -a "$1" != "dog" -a "$1" != "horse" ];then echo no else echo yes fi }
Quindi usa semplicemente in questo modo:
word_valid cat
Risposta
stavo cercando una soluzione “una riga” per convalidare largomento del mio script e ho utilizzato Joseph R. answer qui sopra con:
[[ "$ARG" =~ ^(true|false)$ ]] || { echo "Argument received invalid value" ; exit 1 ; }
Risposta
Tu potrebbe utilizzare fgrep per specificare tutte le parole consentite:
if $(echo "$WORD" | fgrep -wq -e dog -e cat -e horse) ; then echo yes else echo no fi
Il flag -w
corrisponde solo alle parole intere, il -q
il flag lo fa funzionare silenziosamente (perché tutto ciò di cui abbiamo bisogno è il valore di ritorno per listruzione if da utilizzare) e ogni -e
pattern specifica un pattern per consentire.
fgrep
è la versione di grep che esegue la normale corrispondenza delle stringhe invece della corrispondenza regolare. Se hai grep
, dovresti avere fgrep
, ma in caso contrario, “è identico a utilizzare grep
con il flag -F
(quindi dovresti semplicemente sostituire fgrep -wq
sopra con grep -Fwq
).
Risposta
Questo ha funzionato per me:
#!/bin/bash phrase=(cat dog parrot cow horse) findthis=parrot for item in ${phrase[*]} do test "$item" == "$findthis" && { echo "$findthis found!"; break; } done
Risposta
Potresti voler inserire lelenco di parole in un file, nel caso in cui cambi lelenco spesso, o lo desideri essere condiviso da più script. E potresti dover inserire le parole in un file se lelenco diventa troppo lungo per essere gestito in uno script. Quindi puoi dire
if fgrep –qx "$WORD" word_list
Commenti
- no, non ‘ voglio avere il mio elenco in un file
Risposta
Se le parole sono un elenco in cui i valori sono separati da una nuova riga, puoi fare:
WORDS="$(ls -1)" if echo "${WORDS}" | grep --quiet --line-regexp --fixed-strings "${WORD}"; then echo yes else echo no fi
Risposta
Ho appena avuto lo stesso problema e ho trovato una soluzione sorprendentemente comprensibile che non richiede alcuna conoscenza di regex.
Tieni presente che il la soluzione mostrata di seguito potrebbe essere solo bash, perché non ho idea delle differenze tra bash e altre shell. Inoltre, il manuale di bash avverte che questo tipo di corrispondenza di pattern è lento se la stringa che deve essere trovata è lunga.
WORD=abc [[ "$WORD" == @(def|abc|ghi|foo|barbaz) ]] && echo Word is in set.
Come funziona?Non voglio ripetere qui grandi porzioni del manuale di bash, ma con parole mie:
Se loperatore binario ==
viene utilizzato con il comando composto [[
, la parola a destra delloperatore viene sottoposta a corrispondenza di pattern come spiegato nella sezione ” Pattern di corrispondenza ” nel manuale di bash. Inoltre, in queste condizioni, durante la corrispondenza, si presume che lopzione shell extglob
sia impostata (indipendentemente dallimpostazione effettiva); questa è il punto chiave per comprendere quanto sopra.
Ma cosa succede se le parole nel tuo set contengono già caratteri che hanno un significato speciale nella corrispondenza dei modelli, nella sostituzione dei comandi e in altre espansioni? Il rimedio è semplice: usa qualcosa come
[[ "$WORD" == @("a*"|abc|"?ghi"|"$DontExpandMe"|barbaz) ]] && echo Word is in set.
Ho trovato molto semplice, comprensibile ed efficiente (purché $WORD
sia breve) soluzione che non ha effetti collaterali o è da ngerous come i metodi basati su set
.
shopt -s nocasematch
potrebbe essere utile se desideri che la ricerca non faccia distinzione tra maiuscole e minuscole.[[
e]]
–[
e]
non sono sufficienti.[[ "$ARG" =~ ^(true|false)$ ]] || { echo "Argument received invalid value" ; exit 1 ; }
egrep -q "^$WORD$" /tmp/words; [[ $? != 0 ]] && echo "Not found" || echo "OK"
.