Come utilizzare le variabili tra virgolette singole


11

Ho un'applicazione che assume come input attributi tra virgolette doppie incorporate tra virgolette singole. Prendi ad esempio questo comando giusto:

command -p 'cluster="cl1"'

Per automatizzarlo, ho creato un file bash usando $CLUSTERcome variabile. Come dovrebbe essere il mio comando? In altre parole, cosa dovrei mettere al posto di cl1?

Nota che, se ho modificato il comando sopra, non sarà accettato. Ad esempio: command -p "cluster=cl1"non è accettato


2
CLUSTER='"cl1"'; command -p "cluster=$CLUSTER"
Mikeserv,

Un'altra possibilità (se si preferisce memorizzare clisenza virgolette all'interno della CLUSTERvariabile):CLUSTER='cl1'; command -p 'cluster="'"$CLUSTER"'"'
jimmij

Alla fine ho trovato la risposta giusta. Grazie @jimmij.
Mohamad-Jaafar NEHME,

Risposte:


8

Sembra che il tuo comando stia forse impostando le variabili di ambiente in base agli argomenti forniti nella riga di comando. Può darsi che tu possa fare:

CLUSTER=cl1; cluster=$CLUSTER command

... e imposta il suo ambiente per esso su invito.

Altrimenti, le citazioni di shell in genere delimitano gli argomenti o sfuggono ad altri caratteri di shell speciali dall'interpretazione della shell. Puoi contenere (e quindi sfuggire) diversi tipi di citazioni di shell all'interno di altri tipi in base a varie regole:

  • "''''" - una stringa tra virgolette può contenere qualsiasi numero di virgolette.
  • "\""- una \barra rovesciata può sfuggire a una "virgoletta all'interno di una "stringa tra virgolette.
    • In questo contesto, una \\barra rovesciata sfugge anche a se stessa, al \$token di espansione e alle \newline come indicato di seguito, ma viene altrimenti trattata letteralmente.
  • "${expand} and then some"- una stringa tra virgolette può contenere $un'espansione della shell interpretata .
  • '"\'- una 'stringa tra virgolette può contenere qualsiasi carattere diverso da una 'virgoletta.
  • \- una barra rovesciata non quotata sfuggirà a qualsiasi personaggio successivo per interpretazione letterale - anche un'altra barra rovesciata - tranne una \newline.
    • In un \\ncaso di ewline sia la \barra rovesciata che la \newline vengono completamente rimosse dal comando interpretato risultante.
  • ${parameter+expand "$parameter"}- le virgolette risultanti da un'espansione della shell non servono quasi mai come delimitatori, tranne alcuni casi speciali. Non mi azzarderò a descriverli qui di seguito.

Ritengo strano che qualsiasi applicazione interpreti le virgolette nei suoi argomenti della riga di comando. Tale pratica non ha molto senso in questo - almeno per le shell - lo scopo principale di una citazione è generalmente di delimitare un argomento. All'invocazione, tuttavia, gli argomenti sono sempre già delimitati da \0NULcaratteri e quindi una citazione non può servire a molto scopo.

Anche una shell in genere si preoccupa di interpretare le virgolette in uno dei suoi argomenti di invocazione quando viene chiamata con un -cinterruttore - il che indica che il suo primo operando è in realtà uno script di shell che dovrebbe essere eseguito su chiamata. Questo è un caso di input valutato due volte .

Detto questo, puoi fare una serie di cose per passare citazioni letterali tramite argomenti sulla riga di comando. Per esempio:

CLUSTER='"cl1"'; command -p "cluster=$CLUSTER"

Come ho notato in un commento prima, puoi contenere le "virgolette all'interno di un'espansione che è a sua volta "citata.

CLUSTER=cl1; command -p "cluster=\"$CLUSTER\""

È possibile uscire "da una \barra rovesciata all'interno della "stringa tra virgolette.

CLUSTER=cl1; command -p cluster='"'"$CLUSTER"'"'

Puoi alternare e concatenare gli stili di quotazione per arrivare al risultato finale desiderato, come indicato sopra nelle note di @jimmij .

CLUSTER=cl1; ( set -f; IFS=; command -p cluster=\"$CLUSTER\" )

È possibile disattivare sia la generazione nome di file e $IFSla scissione - evitando così la necessità di citare il $expansiona tutti - e così citare solo le virgolette. Questo è probabilmente eccessivo.

Infine, esiste un altro tipo di shell-quote che potrebbe essere utilizzato. Come ho notato prima, la sh -c "$scriptlet"forma di invocazione della shell viene spesso utilizzata per fornire lo script di una shell sulla riga di comando. $scriptletTuttavia, quando diventa complicato - come quando le virgolette devono contenere altre virgolette - può spesso essere vantaggioso usare un documento qui e sh -sinvece - in cui la shell è specificatamente incaricata di assegnare tutti i seguenti operandi ai parametri posizionali come farebbe in un -ccaso e tuttavia prendere anche la sua sceneggiatura stdin.

Se il tuo comando deve interpretare le virgolette in questo modo, lo considererei meglio se potesse farlo in un input di file. Per esempio:

CLUSTER=cl1
command --stdin <<-SCRIPT
    cluster="$CLUSTER"
SCRIPT

Se non si cita il delimitatore di a, <<here-documenttutti i suoi contenuti vengono trattati quasi esattamente come se fossero "citati in chiaro - tranne per il fatto che le "doppie virgolette non vengono trattate in modo speciale. E quindi se invece eseguiamo quanto sopra con cat:

CLUSTER=cl1
cat <<-SCRIPT
        cluster="$CLUSTER"
SCRIPT

... stampa ...

cluster="cl1"

1

Come mikeserv ha scritto:

 CLUSTER='"cl1"'; command -p "cluster=$CLUSTER" 

"Double citazione" ogni letterale che contiene spazi / metacaratteri e ogni espansione: "$var", "$(command "$var")", "${array[@]}", "a & b". Utilizzare 'single quotes'il codice o letterale $'s: 'Costs $5 US', ssh host 'echo "$HOSTNAME"'. Vedi
http://mywiki.wooledge.org/Quotes
http://mywiki.wooledge.org/Arguments
http://wiki.bash-hackers.org/syntax/words


Hai ragione, grazie. Ma che dire dell'automazione? Supponiamo che io voglia leggere CLUSTER?
Rimarrò

@Moi - l'automazione non è un grosso problema, anche se dovrai disinfettare la variabile dei "caratteri - solo il primo e l'ultimo dovrebbero essere sufficienti. Il vero problema qui è la tua app che interpreta le citazioni in un arg. L'interpretazione di una citazione in un argomento non è quasi mai una buona idea perché una citazione dovrebbe essere solo un mezzo per delimitare un argomento - e su invito che il delimitazione è gestito da \0NULs in ogni caso. Probabilmente esiste un modo migliore per passare le informazioni che desideri all'app? Come un command --'script=/path/to/some/file'o qualcosa del genere?
Mikeserv,
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.