Non puoi usare il punto esclamativo (!) In bash?


87

Sto cercando di utilizzare il comando curl per accedere a un URL http con un punto esclamativo ( !) nel suo percorso. per esempio:

curl -v "http://example.org/!287s87asdjh2/somepath/someresource"

la console risponde con bash: ... event not found.

Cosa sta succedendo qui? e quale sarebbe la sintassi corretta per sfuggire al punto esclamativo?


Risolto in bash 4.4+
Isaac il

Risposte:


99

Il punto esclamativo fa parte dell'espansione della storia in bash. Per usarlo è necessario racchiuso tra virgolette singole (ad esempio:) 'http://example.org/!132'o per sfuggire direttamente a una barra rovesciata ( \) prima del carattere (ad esempio:) "http://example.org/\!132".

Si noti che tra virgolette, una barra rovesciata prima dell'esclamazione impedisce l'espansione della cronologia, MA in questo caso la barra rovesciata non viene rimossa. Quindi è meglio usare virgolette singole, quindi non stai passando una barra rovesciata letterale curlcome parte dell'URL.


8
"http://example.org/\!132"in realtà si espande senza interpretare la barra rovesciata (motivi di conformità POSIX, credo).
Chris Down

@ Chris, ho cercato di chiarire che era la mia seconda opzione nel testo. Grazie per aver sottolineato il potenziale di confusione.
Daniel Pittman,

6
Per la cronaca: non è portatile provare a fuggire "!". La raccomandazione delle migliori pratiche è di citare sempre (virgolette singole) "!". Correlati: "^" (punto di inserimento), è un carattere non metacaratterico che deve essere quotato per la portabilità. Finalmente, "!" non dovrebbe essere usato in un'istruzione if; usalo come argomento per testare invece se possibile (sempre a causa di Solaris / bin / sh).
Nicholas Wilson,

5
Solo le virgolette singole hanno funzionato per me. zsh stava ancora interpretando \!e doppie virgolette.
orkoden,

1
Su Solaris (vecchia shell pre-XPG4 di immondizia), '^' è un alias per |e viene utilizzato per creare una pipe. Se stai inviando script ai clienti e non puoi essere sicuro di quale shell eseguiranno, devi testarli tutti!
Nicholas Wilson,

61

Oltre alla risposta data da Daniel, puoi anche semplicemente disattivare completamente l'espansione della storia se non la usi con set +H.


19
Disattivare del tutto l'espansione della storia è il miglior consiglio che ho sentito tutto il giorno! L'espansione della storia è pericolosa e bizantina quando ci sono alternative molto migliori (ricerca cronologica incrementale con Ctrl-R) che ti consentono di visualizzare in anteprima e modificare il tuo comando in modo da non sparare alla cieca con il comando !-14che pensavi fosse !-12, oops, è successo rm -rf *. Stai attento. Disabilita l'espansione della cronologia! Evita il !!
aculich

6
Risposta più grande: l'espansione della cronologia rappresenta un enorme rischio per la sicurezza! Può essere usato per attaccare Unix attraverso un URL predisposto.
dan

@aculich, oppure usa semplicemente il comando specificato da POSIX fc -14. Ma è vero che puoi farlo senza abilitare anche l'espansione della cronologia. Personalmente, uso !$e !vie sudo !!e anche git add !vi:$abbastanza spesso da giustificare l'uscita dell'espansione della cronologia attivata.
Wildcard il

Penso che lo aggiungerò ai miei file RC della shell. L'ho sempre usato solo come un "trucco" pulito
TonyH il

17

Personalmente farei virgolette singole, ma per completezza, noterò anche dal momento che è un URL, puoi codificare !come %21, ad es curl -v http://example.org/%21132.


13

Anche questo può fare

curl -v "http://example.org/"'!'"287s87asdjh2/somepath/someresource"
o
curl -v "http://example.org/"\!"287s87asdjh2/somepath/someresource"

Il che funziona perché bash concatena le stringhe adiacenti. Questo approccio è particolarmente utile quando hai altre cose che richiedono l'espansione della shell, quindi non puoi usare virgolette singole per l'intera stringa:

curl -v 'http://example.org/!'"287s87asdjh2/${basepath}/someresource"

!il carattere viene utilizzato per le espansioni della cronologia nel prompt della riga di comando.
quindi questo può essere un problema nel prompt ma non nei file di script della shell.
come puoi vedere, le espansioni della cronologia funzionano anche tra virgolette doppie.


Esistono molti modi per fare in modo che i comandi Unix e le frasi in inglese utilizzino più caratteri di quelli necessari e siano più confusi di quanto non debbano essere. In che modo questo è superiore alla prima / accettata / risposta più votata, vale a dire, mettendo l'intero URL tra virgolette singole?
G-Man,

2
@ G-Man: dice un altro modo per costruire argomenti bash. Non ero a conoscenza di questo metodo. Niente di sbagliato nell'apprendimento di nuove cose.
Sahil Singh,

@SahilSingh Come è nuovo? Concatena tre stringhe, due racchiuse tra virgolette doppie e una racchiusa tra virgolette singole. Non c'è nidificazione qui.
Raffaello

@ G-Man Non è ovvio che quando si mettono 2 stringhe una accanto all'altra vengono concatenate. printf ("ciao" "mondo") funzionerebbe anche in c, ma printf ("ciao" 'w') non funzionerà, quindi vedi sapendo che bash accoglie tali espressioni era una novità per me, ma sono d'accordo punto di vista dell'utilità, questo non è superiore. Mi è piaciuta la risposta, e anche Mark Shust.
Sahil Singh,

2
@ G-Man E 'anche utile quando ci sono altre espansioni stringa uno fa vuole che accada nella stessa stringa. Questo è un modo semplice per separare due tipi di comportamento di quotazione.
WAF

7

Ho riscontrato lo stesso problema e la mia soluzione semplice era usare una variabile:

E=!  
curl -v "http://example.org/${E}287s87asdjh2/somepath/someresource"

Qui la semplicità è che (1) È portatile su shell e comandi (2) Non richiede la conoscenza della sintassi di escape e dei codici ASCII.


3

Da Bash 4.3, ora puoi usare le virgolette doppie per citare il carattere di espansione della cronologia:

$ bash --version
GNU bash, version 4.3...
[...]
$ echo "Hello World!"
Hello World!

questo non funziona al di fuori di echo, l'eco sembra gestirlo in modo diverso da solo
phil294

@Blauhirn Questo non ha nulla a che fare con l'eco e tutto a che fare con il preventivo e la versione di bash che stai eseguendo.
Flimm,

2
Questa risposta è errata e dovrebbe essere eliminata. La tua bashversione non ha nulla a che fare con il botto che non viene espanso, è dovuto al fatto che nel tuo esempio !è seguito da "end of line" e che impedisce alla shell di tentare di espanderlo. Prova echo "!Hello World"e vedrai che bashrisponderà con bash: !Hello: event not found. Vedere il manuale per maggiori dettagli
don_crissti

0

Per coloro che usano git bash in Windows, la risposta accettata da @DanielPittman funziona. Tuttavia, è necessario sostituire la barra rovesciata (\) con una barra (/).

Ad esempio, in Unix, sarebbe simile a questo:

curl https://abc.com/services -H 'Authorization: Bearer 111A80BBZZCnS\!ZR412543s'

Per Windows, sarebbe qualcosa del genere (concentrarsi sulla barra in avanti nella parte dell'intestazione dell'autorizzazione)

curl https://abc.com/services -H 'Authorization: Bearer 111A80BBZZCnS/!ZR412543s'


Questo non ha molto senso. L'argomento è citato singolarmente, quindi indipendentemente dalle barre coinvolte l'esclamazione non comporterà l'espansione della cronologia.
Wildcard il

Ohh hai ragione. Ho pubblicato questa risposta solo perché quando stavo usando la risposta di Daniel (usando la barra rovesciata), viene visualizzato un errore.
SamuelDev,
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.