Come confrontare le stringhe in Bash


Risposte:


1376

Utilizzo delle variabili in istruzioni if

if [ "$x" = "valid" ]; then
  echo "x has the value 'valid'"
fi

Se vuoi fare qualcosa quando non corrispondono, sostituiscilo =con !=. Puoi leggere ulteriori informazioni sulle operazioni sulle stringhe e sulle operazioni aritmetiche nella rispettiva documentazione.

Perché usiamo le virgolette $x?

Vuoi le virgolette in giro $x, perché se è vuoto, il tuo script Bash rileva un errore di sintassi come mostrato di seguito:

if [ = "valid" ]; then

Uso non standard ==dell'operatore

Si noti che Bash consente ==di essere utilizzato per l'uguaglianza con [, ma questo non è standard .

Utilizzare il primo caso in cui le virgolette intorno $xsono facoltative:

if [[ "$x" == "valid" ]]; then

o usa il secondo caso:

if [ "$x" = "valid" ]; then

12
In che modo ciò si riferisce alla risposta accettata fornita nell'errore imprevisto dell'operatore ? Ho avuto lo stesso errore durante l'utilizzo [ "$1" == "on" ]. Modificandolo in ["$ 1" = "on"] il problema è stato risolto.
Piotr Dobrogost,

78
Gli spazi sono necessari.
TAAPSoggiando il

6
@JohnFeminella Quando si scrive in uno script bash, dovrebbe avere un singolo =e non due.
user13107

73
potrebbe valere la pena notare che non è possibile utilizzare [ $x -eq "valid" ]. -eqè l'operatore di confronto per numeri interi, non stringhe.
craq

2
@Alex, In quali casi (se mai) devo usare il pattern ["x$yes" == "xyes"], che sta prefissando sia la variabile che la stringa letteralmente con un x? È una reliquia dei vecchi tempi o è davvero necessaria in alcune situazioni?
lanoxx

142

Oppure, se non hai bisogno di un'altra clausola:

[ "$x" == "valid" ] && echo "x has the value 'valid'"

71
E se hai bisogno di una clausola else e vuoi creare una riga folle: ["$ x" == "valid"] && echo "valid" || echo "invalid"
Matt White

11
@MattWhite: questa è di solito una cattiva idea, come echopuò fallire.
gniourf_gniourf,

1
anche se i gotchas potessero apparire, in modo bello ed elegante sia da marko && MattWhite
Deko,

3
@gniourf_gniourf, nessun problema, usare [ "$X" == "valid" ] || ( echo invalid && false ) && echo "valid" .
12431234123412341234123,

4
@ 12431234123412341234123 { echo invalid && false; }è più efficiente di ( echo invalid && false ), poiché evita di pagare per una subshell non necessaria.
Charles Duffy,

84
a="abc"
b="def"

# Equality Comparison
if [ "$a" == "$b" ]; then
    echo "Strings match"
else
    echo "Strings don't match"
fi

# Lexicographic (greater than, less than) comparison.
if [ "$a" \< "$b" ]; then
    echo "$a is lexicographically smaller then $b"
elif [ "$a" \> "$b" ]; then
    echo "$b is lexicographically smaller than $a"
else
    echo "Strings are equal"
fi

Appunti:

  1. Gli spazi tra ife [e ]sono importanti
  2. >e <sono operatori di reindirizzamento, quindi evitatelo con \>e \<rispettivamente per le stringhe.

6
Grazie per il confronto alfabetico delle stringhe
shadi,

Il mio problema era che in $arealtà " "lo circondava come parte del valore letterale della stringa, quindi ho dovuto usare il carattere escape $bper confrontare i valori. Sono stato in grado di trovare questo dopo l'esecuzione bash -x ./script.sh, il flag -x ti permette di vedere il valore di ogni esecuzione e aiuta nel debug.
ShahNewazKhan,

Si noti che il confronto alfabetico degli ordini non è standardizzato POSIX, quindi non è garantito che funzioni su piattaforme non GNU / shell non bash. Solo le operazioni su pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html sono garantite come portatili.
Charles Duffy,

62

Per confrontare le stringhe con i caratteri jolly utilizzare

if [[ "$stringA" == *$stringB* ]]; then
  # Do something here
else
  # Do Something here
fi

12
È importante che i caratteri jolly possano essere utilizzati solo sul lato destro! Si noti inoltre che mancano "i caratteri jolly. (a proposito: +1 per i caratteri jolly!)
Scz,

6
L'espansione $stringB deve essere citato (e, per inciso, la sinistra non ha bisogno di essere citato): if [[ $stringA = *"$stringB"* ]]; then.
gniourf_gniourf,

sto cercando di utilizzare la stessa logica jolly per il nome file nel percorso file. Ma non funziona per me. ho provato tutte le diverse stringhe jolly fornite qui. ma va sempre nel caso contrario. stringA nel mio caso è un percorso di file / tmp / file e stringB è "file".
Pioggia

35

Devo dissentire su uno dei commenti in un punto:

[ "$x" == "valid" ] && echo "valid" || echo "invalid"

No, non è un folle oneliner

Sembra solo uno a, hmm, il non iniziato ...

Utilizza modelli comuni come lingua, in un certo senso;

E dopo aver imparato la lingua.

In realtà, è bello da leggere

È una semplice espressione logica, con una parte speciale: valutazione pigra degli operatori logici.

[ "$x" == "valid" ] && echo "valid" || echo "invalid"

Ogni parte è un'espressione logica; il primo può essere vero o falso, gli altri due sono sempre veri.

(
[ "$x" == "valid" ] 
&&
echo "valid"
)
||
echo "invalid"

Ora, quando viene valutato, viene verificato il primo. Se è falso, il secondo operando della logica e && dopo non è rilevante. Il primo non è vero, quindi non può essere il primo e il secondo essere vero, comunque.
Ora, in questo caso è il primo lato della logica o || falso, ma potrebbe essere vero se l'altro lato - la terza parte - è vero.

Quindi verrà valutata la terza parte, principalmente scrivendo il messaggio come effetto collaterale. (Ha il risultato 0per true, che non usiamo qui)

Gli altri casi sono simili, ma più semplici - e - lo prometto! sono - possono essere - facili da leggere!
(Non ne ho uno, ma penso che essere un veterano UNIX con la barba grigia aiuta molto in questo.)


17
Di ... && ... || ...solito è malvisto (scusate il veterano Unix con la barba grigia, vi siete sbagliati per tutto questo tempo), dato che non è semanticamente equivalente a if ... then ... else .... Non ti preoccupare, questa è una trappola comune .
gniourf_gniourf il

6
@gniourf_gniourf OP non è sbagliato-- né sono probabilmente ignoranti come tu suggerisci. ... && ... || ...è un modello perfettamente valido e un idioma bash comune. Il suo utilizzo prescrive conoscenze precedenti (che potrebbero essere utili da tenere a mente se ci sono principianti tra il pubblico), ma OP ha i capelli per dimostrare di sapere come evitare i tombini aperti.
ebpa,

3
@ebpa Cosa succede se l'istruzione che segue && restituisce un valore falso, l'esecuzione procederà per l'istruzione seguente || ? Se è così, è sbagliato e forse è ciò che suggerisce gniourf
TSG

4
Pensavo che l'eco fosse solo un esempio. La dichiarazione che segue && potrebbe ancora restituire un valore diverso da zero
TSG

2
@gniourf_gniourf +1 per aver pubblicato il link a Bash Pitfalls! Molto utile!
Jaguar,

21

puoi anche usare use case / esac

case "$string" in
 "$pattern" ) echo "found";;
esac

Questa equivalenza o contiene?
ytpillai,

@ytpillai, è equivalenza. Tieni presente che puoi avere modelli separati da |, prima di ). La indichiarazione è equivalente a thenin ifdichiarazioni. Si potrebbe sostenere che funzioni su un elenco di schemi, in cui ogni elenco ha una propria dichiarazione su cosa fare, se si proviene da Python. Non come substring in string, ma piuttosto for item in list. Utilizzare a *come ultima affermazione se si desidera una elsecondizione. Ritorna al primo incontro.
Mazunki,

18

Lo script seguente legge da un file denominato "testonthis" riga per riga e quindi confronta ogni riga con una stringa semplice, una stringa con caratteri speciali e un'espressione regolare. Se non corrisponde, lo script stamperà la riga, altrimenti no.

Lo spazio in Bash è molto importante. Quindi funzionerà quanto segue:

[ "$LINE" != "table_name" ] 

Ma quanto segue non lo farà:

["$LINE" != "table_name"] 

Quindi per favore usa come è:

cat testonthis | while read LINE
do
if [ "$LINE" != "table_name" ] && [ "$LINE" != "--------------------------------" ] && [[ "$LINE" =~ [^[:space:]] ]] && [[ "$LINE" != SQL* ]]; then
echo $LINE
fi
done

Utilizzare questo approccio per scorrere un file. Cioè, rimuovere l'UUoC tra le altre cose.
fedorqui "SO smettere di danneggiare" il

Non è importante a causa di bashma perché in [realtà è un binario esterno (come in which [produce qualcosa del genere /usr/bin/[)
Patrick Bergner,

11

Probabilmente userei le corrispondenze regexp se l'input ha solo poche voci valide. Ad esempio, solo "start" e "stop" sono azioni valide.

if [[ "${ACTION,,}" =~ ^(start|stop)$ ]]; then
  echo "valid action"
fi

Nota che ho minuscolo la variabile $ACTIONusando la doppia virgola. Inoltre, questo non funzionerà su versioni bash troppo vecchie là fuori.


9

Bash 4+ esempi. Nota: non usare le virgolette causerà problemi quando le parole contengono spazi, ecc. Citano sempre in Bash, IMO.

Ecco alcuni esempi in Bash 4+:

Esempio 1, controlla 'yes' nella stringa (senza distinzione tra maiuscole e minuscole):

    if [[ "${str,,}" == *"yes"* ]] ;then

Esempio 2, controlla "yes" nella stringa (senza distinzione tra maiuscole e minuscole):

    if [[ "$(echo "$str" | tr '[:upper:]' '[:lower:]')" == *"yes"* ]] ;then

Esempio 3, controlla 'yes' nella stringa (case sensitive):

     if [[ "${str}" == *"yes"* ]] ;then

Esempio 4, controlla 'yes' nella stringa (case sensitive):

     if [[ "${str}" =~ "yes" ]] ;then

Esempio 5, corrispondenza esatta (maiuscole e minuscole):

     if [[ "${str}" == "yes" ]] ;then

Esempio 6, corrispondenza esatta (senza distinzione tra maiuscole e minuscole):

     if [[ "${str,,}" == "yes" ]] ;then

Esempio 7, corrispondenza esatta:

     if [ "$a" = "$b" ] ;then

Godere.


per me (mac GNU bash versione 4.4.12 (1) -release x86_64-apple-darwin17.0.0), devo usare if [ "$a"="$b" ]o non funziona ... non può avere spazi attorno agli uguali
spettro

1

L'ho fatto in questo modo compatibile con Bash e Dash (sh):

testOutput="my test"
pattern="my"

case $testOutput in (*"$pattern"*)
    echo "if there is a match"
    exit 1
    ;;
(*)
   ! echo there is no coincidence!
;;esac

qual è la differenza tra usare un precedente (e non usarlo?
Mazunki,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.