Questo è un caso molto oscuro che si potrebbe considerare un bug nel modo [in cui è definito il test integrato; tuttavia, corrisponde al comportamento del file [binario effettivo disponibile su molti sistemi. Per quanto posso dire, colpisce solo alcuni casi e una variabile che ha un valore che corrisponde a un [operatore come (, !, =, -e, e così via.
Lasciami spiegare perché e come aggirarlo nelle shell Bash e POSIX.
Spiegazione:
Considera quanto segue:
x="("
[ "$x" = "(" ] && echo yes || echo no
Nessun problema; quanto sopra non produce alcun errore e produce yes. Ecco come ci aspettiamo che le cose funzionino. '1'Se lo desideri, puoi modificare la stringa di confronto e il valore di x, e funzionerà come previsto.
Si noti che l'attuale /usr/bin/[binario si comporta allo stesso modo. Se si esegue ad es. Non si '/usr/bin/[' '(' = '(' ']'verifica alcun errore, poiché il programma è in grado di rilevare che gli argomenti consistono in una singola operazione di confronto di stringhe.
Il bug si verifica quando noi e con una seconda espressione. Non importa quale sia la seconda espressione, purché sia valida. Per esempio,
[ '1' = '1' ] && echo yes || echo no
produce yesed è ovviamente un'espressione valida; ma, se combiniamo i due,
[ "$x" = "(" -a '1' = '1' ] && echo yes || echo no
Bash rifiuta l'espressione se e solo se xè (o !.
Se dovessimo eseguire quanto sopra usando il [programma vero e proprio
'/usr/bin/[' "$x" = "(" -a '1' = '1' ] && echo yes || echo no
l'errore sarebbe comprensibile: dal momento che la shell esegue le sostituzioni variabili, il /usr/bin/[binario riceve solo i parametri ( = ( -a 1 = 1e la terminazione ], comprensibilmente non riesce a capire se le parentesi aperte avviano o meno un'espressione secondaria, essendo coinvolta un'operazione e un'operazione. Certo, analizzarlo come due confronti di stringhe è possibile, ma farlo avidamente in quel modo potrebbe causare problemi quando applicato a espressioni appropriate con sottoespressioni tra parentesi.
Il problema, in realtà, è che la shell [integrata si comporta allo stesso modo, come se espandesse il valore di xprima di esaminare l'espressione.
(Queste ambiguità, e altre relative all'espansione variabile, sono state una delle ragioni principali per cui Bash ha implementato e ora consiglia invece di utilizzare le [[ ... ]]espressioni di test.)
La soluzione è banale e spesso si vede negli script che usano shshell più vecchie . Aggiungi un carattere "sicuro", spesso x, davanti alle stringhe (entrambi i valori vengono confrontati), per garantire che l'espressione sia riconosciuta come confronto di stringhe:
[ "x$x" = "x(" -a "x$y" = "x1" ]
[[ "$x" = '1' && "$y" = '1' ]]