2009-11-12 16 views
14

Los scripts de Autoconf tienen problemas con un nombre de archivo o ruta de acceso con espacios. Por ejemplo,Variable de shell con espacios, citando para la opción de línea de comando única

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

resultado en (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 

El comando de compilación de ./configure es ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' y no soy capaz de modificar esto (que pude tal vez, pero trabajando alrededor autoconf de esta manera no es una solución general).

Creo que se trata de obtener una variable de shell que contenga espacios para analizar como una sola variable de línea de comandos en lugar de dividirla en espacios. El ejemplo de shell simple que puedo llegar a es crear un archivo con espacios e intentar lista es con ls con una variable de shell como argumento a ls:

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

Esto funciona, pero es ilegal ya que en autoconf I no puede modificar el código shell:

$ ls "$file" 
a b 

Ninguno de los siguientes intentos de citar cosas funcionan:

$ 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\\"`" 

y así sucesivamente.

¿Es esto imposible de lograr en los scripts de shell? ¿Existe un presupuesto mágico que expanda una variable de shell con espacios en un solo argumento de línea de comando?

Respuesta

8

Debería intentar establecer la variable de entorno $IFS.

del manual de bash (1):

IFS - El separador de campo interno que se utiliza para la división de palabras después de la expansión y de dividir las líneas en palabras con la lectura orden interna comando. El valor predeterminado es '' pestaña de espacio nueva línea ''.

Por ejemplo

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

No se olvide de establecer $IFS espalda o cosas extrañas sucederá.

+5

Establecería IFS en una cadena nula; Funciona igual de bien. 'saveIFS =" $ IFS "; IFS = ''; ls $ archivo; IFS = "$ saveIFS" ' –

0

Usar comillas es interesante. Desde (ligeramente) leyendo la página bash man creí que tenías que escapar del espacio con \, así "/ ruta con espacio" se convierte en/ruta \ con \ espacio. Nunca he probado las comillas, pero parece que no trabaja en general (tu ejemplo). Escapar funciona con ls sin cotización y sin cambiar IFS.

¿Qué ocurre si utiliza el formato de "espacios de escape" del comando?

+0

El punto es usar' ls' como una prueba y no tocar su argumento. El requisito es ser capaz de hacer 'ls $ file' exactamente así y solo hacer cambios en' file = "a b" '. Esto es análogo a cambiar el argumento a 'configure' sin modificar los archivos involucrados. –

4

si se le da comando

gcc -I"x y z" 

en una cáscara de entonces, ciertamente, el único parámetro de línea de comandos "-Ix y z" se pasará a gcc. No hay duda de eso. Ese es todo el significado de las comillas dobles: las cosas entre comillas dobles NO están sujetas a la división de campos, y por lo tanto no están sujetas a $ IFS, por ejemplo.

Pero debe tener cuidado con el número de citas que necesita. Por ejemplo, si usted dice

file="a b" # 1 

y luego te dicen

ls $file # 2 

lo que sucede es que el contenido de la variable de archivo son 'a b', no ' 'ab'', debido a que las comillas dobles eran "comido" cuando se analizó la línea 1. El valor reemplazado está entonces separado del campo y obtienes ls en dos archivos 'a' y 'b'. La forma correcta de obtener lo que desea es

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

Ahora el problema en su caso original es que cuando se establece una variable de una cadena que contiene comillas dobles, las comillas dobles se tarde no interpretan como símbolos de cotización cáscara pero solo como letras normales Razón por la cual, cuando haces algo como

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

realidad la cáscara tokenizes el contenido de la variable de fichero en "a" y 'b"' cuando se analiza el comando ls; la comilla doble ya no es un carácter de comillas, sino solo una parte de los contenidos de la variable. Es análogo a que si establece

file="\$HOME"; ls $file 

se produce un error de ese directorio '$ HOME' no existe ningún entorno de búsqueda --- variable toma su lugar.

Así que las mejores opciones son

  1. Hack autoconf
  2. No utilice nombres de ruta con espacios (la mejor solución)
1

desea citar todo el argumento, en cualquiera de estas formas :

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

El comando ./configure entonces ve una sola argum ent

"CPPFLAGS=-I/path with space" 

que se analiza como un parámetro denominado «CPPFLAGS» que tiene el valor «-I/path with space»(corchetes añadido para mayor claridad).

2

Usar espacio en nombres de directorio en el mundo Unix es simplemente pedir problemas. No es solo el problema de citar en scripts de shell (lo que debe hacerse de todos modos): algunas herramientas simplemente no pueden hacer frente a los espacios en los nombres de archivo. Por ejemplo, no puede (portablemente) escribir una regla Makefile que dice construir "baz.o" de "foo bar/baz.c".

En el caso de CPPFLAGS por encima de lo haría en orden de preferencia:

  1. arreglar el sistema no utiliza ningún espacio de uso en los nombres de directorio
  2. escribir un pequeño envoltorio sobre el compilador y llaman ./configure CC=mygcc. En ese caso, mygcc podría ser
     
    
    

    !/bin/sh

    gcc "-I/foo bar/include" "[email protected]"
  3. crear un enlace simbólico (p./tmp/mypath) a la ruta temido y utilizar CPPFLAGS=-I/tmp/mypath
0
$ file="\"a b\"" 

$ eval ls $file 
+1

Esto no resolverá el problema porque el script de autoconf necesitará modificaciones para llamar a eval. El objetivo de la pregunta es evitar hacer esa modificación. –

0

Todo depende de cómo se utiliza la variable. En primer lugar, tenga en cuenta que si usa Autoconf, esto probablemente signifique que se utilizará make con el tiempo, de modo que las reglas estén dictadas por make y, en particular, por las reglas predeterminadas make. Aunque es posible que desee utilizar sus propias reglas exclusivamente, las cosas deben seguir siendo consistentes entre las herramientas, y algunas variables tienen significados estándar, por lo que no desea desviarse de ellas. Este no es el caso de CPPFLAGS, pero esto debe seguir siendo similar a CFLAGS, que es estándar. Consulte POSIX make utility, donde las variables simplemente se expanden con la división de palabras estándar sh, que no proporciona ningún mecanismo de cotización (el separador de campo está controlado por $IFS, pero no cambia la variable IFS para aceptar espacios como caracteres normales ya que esto romperá otras cosas , como poder proporcionar varias opciones de -I y/o -L en tales variables de la manera estándar).

Dado que existe tal limitación con make, supongo que sería inútil intentar evitar esta limitación en Autoconf.

Ahora, dado que un espacio es necesariamente un separador de campo, la única posibilidad es proporcionar rutas de acceso sin caracteres de espacio. Si los espacios en los nombres de las rutas fueran compatibles en el futuro, esto probablemente se haría a través de la codificación del nombre de ruta, con la decodificación en la UI de alto nivel (un poco como con las URL). Alternativamente, si tiene la opción y realmente quiere usar espacios en nombres de rutas, puede usar algún espacio que no sea ASCII (Por cierto, así es como el sistema operativo RISC admite espacio en nombres de rutas, forzándolo a ser el espacio sin interrupciones).

Cuestiones relacionadas