2009-11-12 5 views
14

Gli script di Autoconf hanno problemi con un nome file o percorso con spazi. Ad esempio,Variabile di shell con spazi, che indica un'opzione di riga di comando singola

./configure CPPFLAGS="-I\"/path with space\"" 

risultati in (config.log):

configure:3012: gcc -I"/path with space" conftest.c >&5 
gcc: with: No such file or directory 
gcc: space": No such file or directory 

Il comando di compilazione da ./configure è ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' e io non sono in grado di modificare questo (ho potuto, forse, ma di lavoro intorno autoconf in questo modo non è una soluzione generale).

Penso che si tratti di ottenere una variabile di shell che contenga spazi da analizzare come una singola variabile da riga di comando anziché dividere gli spazi. L'esempio più semplice guscio posso venire in mente è di creare un file con gli spazi e si tenta di lista è con ls con una variabile di shell come argomento per ls:

$ touch "a b" 
$ file="a b" 
$ ls $file 
ls: a: No such file or directory 
ls: b: No such file or directory 

Questo funziona, ma è illegale poiché in autoconf I non può modificare il codice shell:

$ ls "$file" 
a b 

Nessuno dei seguenti tentativi di citare le cose funzionano:

$ file="\"a \"b"; ls $file 
ls: "a: No such file or directory 
ls: b": No such file or directory 
$ file="a\ b" 
$ file="a\\ b" 
$ file="`echo \\"a b\\"`" 

e così via.

È impossibile eseguire gli script di shell? C'è una citazione magica che espanderà una variabile di shell con spazi in un singolo argomento della riga di comando?

risposta

8

Si dovrebbe provare a impostare la variabile di ambiente $IFS.

da man bash (1):

IFS - il campo separatore interno che viene usato per la suddivisione dopo l'espansione e per dividere le linee in parole con l'incorporato read comando. Il valore predefinito è '' space tab newline ''.

Per esempio

IFS=<C-v C-m> # newline 
file="a b" 
touch $file 
ls $file 

Non dimenticare di impostare $IFS schiena o cose strane accadrà.

+5

Imposterei IFS su una stringa nulla; funziona altrettanto bene. 'saveIFS = "$ IFS"; IFS = ''; ls $ file; IFS = "$ saveIFS" ' –

0

L'utilizzo delle virgolette è interessante. Da (leggermente) leggendo la pagina man di bash ho pensato che dovevi sfuggire allo spazio con \, quindi "/ percorso con lo spazio" diventa/percorso \ con \ spazio non ho mai provato le virgolette, ma sembra che non lo faccia lavoro in generale (il tuo esempio). Escaping funziona con ls senza quotare e senza cambiare IFS.

Cosa succede se si utilizza il formato "spazi di escape" del comando?

+0

Il punto è usare' ls' come test e non toccare il suo argomento. Il requisito è essere in grado di fare 'ls $ file' esattamente come quello e solo apportare modifiche a' file = "a b" '. Questo è un analogo al cambiamento dell'argomento di 'configure' senza modificare i file coinvolti. –

4

se si dà il comando

gcc -I"x y z" 

in un guscio allora certamente il parametro di un'unica riga di comando "-Ix y z" saranno passati a gcc. Non c'è dubbio a questo. Questo è l'intero significato delle doppie virgolette: le cose tra virgolette non sono soggette alla divisione del campo, e quindi non sono soggette a $ IFS, per esempio.

Ma è necessario fare attenzione al numero di preventivi necessari. Per esempio, se si dice

file="a b" # 1 

e poi dici

ls $file # 2 

ciò che accade è che il contenuto della variabile del file sono 'a b', non e ' 'ab'', perché le doppie virgolette sono stati "mangiato" quando la riga 1 è stata analizzata. Il valore sostituito viene quindi separato dal campo e ottieni ls su due file 'a' e 'b'. Il modo corretto per ottenere quello che vuoi è

file="a b"; ls "$file" 

Ora il problema nel tuo caso originale è che quando si imposta una variabile in una stringa che contiene virgolette doppie, le virgolette sono entro e non interpretati come simboli della shell di citazione ma proprio come normali lettere. È per questo che quando si fa qualcosa di simile

file="\"a b\""; ls $file 

in realtà il guscio tokenizza il contenuto della variabile file in ' "a' e 'b"' quando il comando ls viene analizzato; la virgoletta doppia non è più un carattere di citazione della shell ma solo una parte dei contenuti della variabile. E 'analogo a quello se si imposta

file="\$HOME"; ls $file 

si ottiene un errore che directory '$ HOME' non esiste --- nessun ambiente di ricerca variabile avviene.

Così i vostri migliori opzioni sono

  1. Hack autoconf
  2. Non utilizzare nomi di percorso con gli spazi (soluzione migliore)
1

Si vuole citare l'intero argomento, in uno dei seguenti modi :

./configure "CPPFLAGS=-I/path with space" 
./configure CPPFLAGS="-I/path with space" 

Il comando ./configure vede quindi un unico argum ent

"CPPFLAGS=-I/path with space" 

che viene analizzato come un parametro denominato «CPPFLAGS» che ha il valore «-I/path with space»(parentesi aggiunte per chiarezza).

2

L'utilizzo dello spazio nei nomi di directory nel mondo Unix richiede semplicemente problemi. Non è solo il problema di citare script di shell (che devono comunque essere fatti bene): alcuni strumenti semplicemente non possono far fronte agli spazi nei nomi dei file. Ad esempio, non è possibile scrivere in modo trasportabile una regola Makefile che dice build "baz.o" da "foo bar/baz.c".

Nel caso di CPPFLAGS sopra lo farei in ordine di preferenza:

  1. riparare il sistema non usa l'utilizzo alcuno spazio nei nomi di directory
  2. scrivere un piccolo wrapper per il compilatore e chiamare ./configure CC=mygcc. In tal caso, mygcc potrebbe essere
     
    
    

    !/bin/sh

    gcc "-I/foo bar/include" "[email protected]"
  3. creare un collegamento simbolico (ad es./tmp/mypath) al percorso temuto e utilizzare CPPFLAGS=-I/tmp/mypath
0
$ file="\"a b\"" 

$ eval ls $file 
+1

Questo non risolverà il problema perché lo script autoconf avrà bisogno di modifiche per chiamare eval. Il punto della domanda è evitare di fare quella modifica. –

0

Tutto dipende da come viene utilizzata la variabile. Prima di tutto, si noti che se si utilizza Autoconf, questo probabilmente significa che alla fine verrà utilizzato make, in modo che le regole siano dettate da make e, in particolare, dalle regole predefinite make. Anche se potresti voler utilizzare esclusivamente le tue regole, le cose devono rimanere coerenti tra gli strumenti e alcune variabili hanno significati standard, in modo che tu non voglia discostarti da esse. Questo non è il caso di CPPFLAGS, ma questo dovrebbe rimanere simile a CFLAGS, che è standard. Vedere lo POSIX make utility, dove le variabili vengono semplicemente espanse con la divisione di parole standard sh, che non fornisce alcun meccanismo di quotatura (il separatore di campo è controllato da $IFS, ma non modifica la variabile IFS in modo da accettare spazi come caratteri normali poiché ciò interromperà altre cose , come essere in grado di fornire diverse opzioni -I e/o -L in tali variabili con il metodo standard).

Poiché esiste una tale limitazione con make, suppongo che sarebbe inutile cercare di evitare questa limitazione in Autoconf.

Ora, poiché uno spazio è necessariamente un separatore di campo, l'unica possibilità è fornire percorsi senza caratteri di spazio. Se in futuro dovessero essere supportati gli spazi nei nomi di percorso, questo probabilmente verrebbe fatto tramite la codifica del percorso, con la decodifica nell'interfaccia utente di alto livello (un po 'come con gli URL). In alternativa, se si ha la scelta e si vuole veramente usare spazi nei nomi di percorso, è possibile utilizzare uno spazio non ASCII (BTW, questo è il modo in cui RISC OS supporta lo spazio nei percorsi, forzandolo a essere lo spazio senza interruzioni).

Problemi correlati