Andare alla directory usando le variabili bash non funziona quando i nomi delle directory hanno spazi


11

Diciamo che voglio memorizzare il seguente comando in una variabile

cd "/cygdrive/c/Program Files/"

Quindi faccio questo

dir="cd \"/cygdrive/c/Program Files/\""

Ciò dovrebbe archiviare il comando per navigare nella directory Programmi, quindi quando digito $ dir mi porta a quella directory. Per verificare che le citazioni siano state correttamente ignorate, scrivo

echo $dir

che mi dà

cd "/cygdrive/c/Program Files/"

Quindi tutto dovrebbe funzionare bene. Tuttavia, quando scrivo,

$dir

ottengo

bash: cd: "/cygdrive/c/Program: No such file or directory

Che cosa sto facendo di sbagliato? Sto usando Cygwin, ma presumo che questo problema si applichi a bash in generale.


Prova a rimuovere le virgolette attorno al nome della directory e, invece, evita lo spazio con una barra rovesciata.
Mike Fitzpatrick,

Risposte:


8

Risposta breve: vedi BashFAQ # 050 ("Sto cercando di inserire un comando in una variabile, ma i casi complessi falliscono sempre!").

Risposta lunga: quando bash analizza un comando, analizza le virgolette prima di sostituire le variabili; non torna mai indietro e analizza nuovamente le virgolette nei valori delle variabili, quindi finiscono per non fare nulla di utile. L'uso di echo per controllare il comando è completamente fuorviante perché mostra il comando dopo che è stato analizzato; se vuoi vedere cosa viene realmente eseguito usa o set -xper avere i comandi di stampa della shell mentre vengono eseguiti, oppure usa printf "%q " $dir; echoinvece di semplice eco.

Se si desidera memorizzare un comando complesso (ovvero uno con spazi o altri caratteri speciali nelle "parole"), è necessario inserirlo in un array anziché in una semplice variabile di testo, quindi espanderlo con il linguaggio `" $ { array [@]} ", in questo modo:

dir=(cd "/cygdrive/c/Program Files/")
"${dir[@]}"

Ora, se lo scopo è creare una scorciatoia facile da scrivere, questa non è chiaramente la strada da percorrere. Utilizzare invece un alias di shell o una funzione:

alias dir='cd "/cygdrive/c/Program Files/"'
dir

o

dir() { cd "/cygdrive/c/Program Files/"; }
dir

7

Quando bash si espande $dir, esegue solo la suddivisione delle parole e il globbing su di esso. La suddivisione in parole produce tre parole: cd, "/cygdrive/c/Programe Files/". Quindi il comando da eseguire è cdcon due argomenti; cdesamina solo il suo primo argomento "/cygdrive/c/Program, che non è una directory esistente.

Se si desidera eseguire una valutazione completa della shell sul contenuto di una variabile, utilizzare eval:

eval "$dir"

Nota che hai bisogno delle doppie virgolette $dir, altrimenti la divisione delle parole verrebbe prima eseguita, quindi evalconcatenerebbe i suoi argomenti con gli spazi. Questo accadrà qui, ma andrebbe male in generale (ad esempio se ci fossero due spazi consecutivi in ​​un nome di file).

Tuttavia, una stringa non è il modo giusto per archiviare un comando shell che si desidera eseguire. A meno che tu non abbia un requisito insolito, dovresti invece utilizzare una funzione:

dir () {
  cd "/cygdrive/c/Program Files/"
}

Se sei davvero interessato a digitare $dirper passare a una directory specifica e questo non è solo un semplice esempio, poiché bash 4, inserisci il shopt -s autocdtuo .bashrce imposta

dir="/cygdrive/c/Program Files/"

dopodiché puoi digitare solo "/cygdrive/c/Program Files/"o "$dir"al prompt della shell per passare a quella directory. Hai ancora bisogno delle doppie virgolette in giro $dir; se non ti piace, usa zsh invece di bash.


6

Memorizzare i comandi nelle variabili non è generalmente una buona idea. Ecco a cosa servono funzioni e alias.

Piuttosto che

dir="cd \"/cygdrive/c/Program Files/\""

prova uno di questi:

dir="/cygdrive/c/Program Files"
...
cd "$dir"

o

dir() { cd "/cygdrive/c/Program Files"; }
dir

o

alias dir='cd "/tmp/Program Files"'
...
dir

Il primo modulo, che memorizza il nome della directory in una variabile, significa un po 'più di battitura, ma è più chiaro quando si esegue il comando che si sta eseguendo un cd. Il secondo è il più vicino a ciò che stai cercando di realizzare. (Non uso molto gli alias in bash; in realtà non sono sicuro di quale vantaggio abbiano rispetto alle funzioni.)

MODIFICARE :

Ed dirè probabilmente un brutto nome per un alias o una funzione, dato che esiste un comando esistente con quel nome (è fondamentalmente una versione di ls, almeno se hai coreutils GNU).


votato perStoring commands in variables is generally not a good idea. That's what functions and aliases are for.
Rob

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.