Come utilizzare una variabile di ambiente all'interno di una stringa tra virgolette in Bash


91

Ho provato varie forme di quanto segue in uno script bash:

#!/bin/bash
svn diff $@ --diff-cmd /usr/bin/diff -x "-y -w -p -W $COLUMNS"

Ma non riesco a ottenere la sintassi per espandere correttamente la COLUMNSvariabile di ambiente.

Ho provato varie forme di quanto segue:

svn diff $@ --diff-cmd /usr/bin/diff -x '-y -w -p -W $COLUMNS'

e

svn diff $@ --diff-cmd /usr/bin/diff -x '-y -w -p -W ${COLUMNS}'

e

eval svn diff $@ --diff-cmd /usr/bin/diff -x "-y -w -p -W $COLUMNS"

Suggerimenti?


quindi cosa producono questi esempi nel tuo caso? E cosa vuoi che producano?

il comando fuori dallo script funziona?
DFA

Hai provatosvn diff $@ --diff-cmd /usr/bin/diff -x "-y -w -p -W ""$COLUMNS"
Qian Chen

A proposito, l'uso di $@non quotato lo rende esattamente uguale a $*- vale a dire che si divide "foo bar"in due argomenti separati fooe bar. Se vuoi conservare l'elenco degli argomenti originale così come ti è stato fornito, lo desideri "$@".
Charles Duffy,

Risposte:


16

In caso di dubbi, potresti utilizzare la richiesta "cols" sul terminale e dimenticare COLUMNS:

COLS=$(tput cols)

Per qualsiasi motivo, questa è l'unica soluzione che sono riuscito a far funzionare da questa pagina (a partire dall'11 / May 10:38 ET). Grazie
Jamie,

397

Solo una breve nota / riepilogo per chi è venuto qui tramite Google alla ricerca della risposta alla domanda generale posta nel titolo (come lo ero io). Uno dei seguenti dovrebbe funzionare per ottenere l'accesso alle variabili di shell tra virgolette:

echo "$VARIABLE"
echo "${VARIABLE}"

L'uso di virgolette singole è il problema principale. Secondo il manuale di riferimento di Bash :

Racchiudere i caratteri tra virgolette singole ( ') preserva il valore letterale di ogni carattere tra virgolette. Una singola virgoletta potrebbe non essere presente tra virgolette singole, anche se preceduta da una barra rovesciata. [...] Racchiudere caratteri in virgolette doppie ( ") conserva il valore letterale di tutti i caratteri all'interno delle virgolette, ad eccezione di $, `, \e, quando l'espansione della cronologia è abilitata, !. I caratteri $e `mantengono il loro significato speciale tra virgolette doppie (vedere Espansioni shell). Il backslash mantiene il suo significato speciale solo quando seguito da uno dei seguenti caratteri: $, `, ",\o una nuova riga. All'interno di virgolette doppie, le barre rovesciate seguite da uno di questi caratteri vengono rimosse. I backslash che precedono i caratteri senza un significato speciale non vengono modificati. Una virgoletta doppia può essere citata tra virgolette doppie precedendola con una barra rovesciata. Se abilitato, l'espansione della cronologia verrà eseguita a meno che non !venga evitato un carattere di escape tra virgolette doppie utilizzando una barra rovesciata. La barra rovesciata che precede !non viene rimossa. I parametri speciali *e @hanno un significato speciale quando sono racchiusi tra virgolette doppie (vedere Espansione dei parametri della shell).

Nel caso specifico posto nella domanda, $ COLUMNS è una variabile speciale che ha proprietà non standard (vedere la risposta di lhunath sopra).


20
Nel caso di singoli apici, forse questa soluzione aiuta: 'before'"$variable"'after'(come indicato in questa risposta: stackoverflow.com/a/13802438/2254346 )
MakisH

Bella risposta! Ho avuto lo stesso problema di fare riferimento alla mia variabile env tra virgolette singole. Dopo aver modificato le virgolette singole in virgolette doppie, la mia variabile env è stata espansa come previsto.
Binita Bharati

14

Nota che COLUMNSè:

  1. NON una variabile d'ambiente. È un parametro bash ordinario impostato dalla stessa bash.
  2. Impostato automaticamente alla ricezione di un SIGWINCHsegnale.

Quel secondo punto di solito significa che la tua COLUMNSvariabile sarà impostata solo nella tua shell interattiva , non in uno script bash.

Se il tuo script stdinè connesso al tuo terminale, puoi cercare manualmente la larghezza del tuo terminale chiedendo al tuo terminale:

tput cols

E per usarlo nel tuo comando SVN:

svn diff "$@" --diff-cmd /usr/bin/diff -x "-y -w -p -W $(tput cols)"

(Nota: dovresti citare "$@" e stare lontano da eval;-))


Grazie per l'informazione; sapere cosa sta succedendo porta un senso di catarsi al problema.
Jamie

2

Il seguente script funziona per me per più valori di $COLUMNS. Mi chiedo se non ti stai impostando COLUMNSprima di questa chiamata?

#!/bin/bash
COLUMNS=30
svn diff $@ --diff-cmd /usr/bin/diff -x "-y -w -p -W $COLUMNS"

Puoi echeggiare $COLUMNSall'interno del tuo script per vedere se è impostato correttamente?


Boo, hiss re: unquoted $@- che divide un singolo parametro "two words"in due parametri separati, twoe words. Dovrebbe essere "$@"passare l'elenco degli argomenti esattamente come è stato fornito.
Charles Duffy,

0

Lo stai facendo bene, quindi immagino che qualcos'altro sia in colpa (non esportare COLUMNS?).

Un trucco per eseguire il debug di questi casi è creare un comando specializzato (una chiusura per i ragazzi del linguaggio di programmazione). Crea uno script di shell chiamato diff-colonne facendo:

exec /usr/bin/diff -x -y -w -p -W "$COLUMNS" "$@"

e basta usare

svn diff "$@" --diff-cmd  diff-columns

In questo modo il tuo codice è più pulito da leggere e più modulare (approccio dall'alto verso il basso), e puoi testare il codice delle colonne diff completamente separatamente (approccio dal basso verso l'alto).


La riga di comando viene analizzata prima che il processo venga biforcato, quindi non esportare COLUMNS non può essere il problema.
Peter van der Heijden

1
Dice che il suo codice è parte di uno script bash, quindi può essere il problema.
Colas Nahaboo
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.