¿Detener la expansión de caracteres comodín de shell?


88

¿Hay alguna forma de que un programa de línea de comandos compilado le diga a bash o csh que no quiere que se expandan los caracteres comodín en sus parámetros?

Por ejemplo, uno podría querer un comando de shell como:

foo *

para simplemente devolver el valor ASCII numérico de ese carácter.

Respuestas:


119

No. La expansión tiene lugar antes de que se ejecute realmente el comando.
Solo puede desactivar el glob antes de ejecutar el comando o citando la estrella.

$ # quote it
$ foo '*'

$ # or escape it
$ foo \*

$ # or disable the glob (noglob)
$ set -f
$ foo *

$ # alternative to set -f
$ set -o noglob
$ # undo it by 
$ set +o noglob

3
además, si no hay nada que expandir, no hay expansión. es decir, con un vacío pwd, echo *es solo*
sam boosalis

7
@sam Esto realmente depende de cómo estén configuradas sus opciones. De tldp: "Si no se encuentran nombres de archivo coincidentes y la opción de shell nullglobestá desactivada, la palabra se deja sin cambios. Si la nullglobopción está configurada y no se encuentran coincidencias, la palabra se elimina".
Chris Middleton

gracias, debería haber calificado que eso fue solo por observación, no por comprensión.
sam boosalis

@ c00kiemon5ter ¿Cómo deshacer el set -f? ¿Es unset -f?
Nam G VU

1
@NamGVUset +f
Yngvar Kristiansen

62

Si bien es cierto que un comando por sí mismo no puede desactivar el globbing, es posible que un usuario le diga a un shell de Unix que no use un comando glob en particular. Esto generalmente se logra editando los archivos de configuración de un shell. Suponiendo que el comando foose puede encontrar a lo largo de la ruta del comando, sería necesario agregar lo siguiente al archivo de configuración apropiado:

Para las conchas sh, bash y ksh:

alias foo='set -f;foo';foo(){ command foo "$@";set +f;}

Para los shells csh y tcsh:

alias foo 'set noglob;\foo \!*;unset noglob'

Para el shell zsh:

alias foo='noglob foo'

No es necesario utilizar la ruta del comando. Digamos que el comando foo está almacenado en el directorio ~ / bin, entonces lo anterior se convertiría en:

Para las conchas sh, bash y ksh:

alias foo='set -f;foo';foo(){ ~/bin/foo "$@";set +f;}

Para los shells csh y tcsh:

alias foo 'set noglob;$home/bin/foo \!*;unset noglob'

Para el shell zsh:

alias foo='noglob ~/bin/foo'

Todo lo anterior se probó con OSX 10.9.2 de Apple. Nota: Al copiar el código anterior, tenga cuidado de eliminar cualquier espacio. Pueden ser importantes.

Actualizar:

El usuario geira ha señalado que en el caso de un shell bash

alias foo='set -f;foo';foo(){ ~/bin/foo "$@";set +f;}

podría ser reemplazado con

reset_expansion(){ CMD="$1";shift;$CMD "$@";set +f;}
alias foo='set -f;reset_expansion ~/bin/foo'

lo que elimina la necesidad de la función foo.

Algunos sitios web utilizados para crear este documento:


3
Esta debería haber sido la respuesta aceptada, ya que demuestra que de hecho es posible hacer lo que quiere el OP. Para conocer algunos métodos aún mejores en bash, este enlace documenta las diversas opciones: blog.edwards-research.com/2011/05/preventing-globbing
geira

@geira: A veces se acepta una respuesta antes de que se publique una respuesta mejor. Creo que este puede ser uno de esos casos. También creo que la respuesta marcada como la más útil para los usuarios termina primero. Nota: agregué su entrada a mi respuesta.
David Anderson

@geira, el OP quiere que el programa compilado se comunique con el shell; responder que es posible configurar el shell para que se comporte como se desee comando por comando es una respuesta útil, y yo mismo aceptaría esta, pero veo espacio para no estar de acuerdo sobre si está completamente en el punto.
Charles Duffy

El hecho de que pueda hacerse no significa que deba hacerse. Hacer que el comportamiento del shell cambie de la expectativa razonable del usuario para los comandos seleccionados suena como sorprendente y, en última instancia, indeseable.
tripleee

@tripleee: Hubo un tiempo en que la gente esperaba relés y tubos de vacío. Se esperaba que se perforaran agujeros en tarjetas de cartón y cinta de papel. La gente tenía reglas de cálculo en lugar de calculadoras y teléfonos. Supongo que para ti esto sería deseable. No me importaron mucho esos tiempos. Disfruto viendo lo que sigue.
David Anderson

8

La expansión la realiza el shell antes de ejecutar el programa. Su programa no tiene ni idea de si se ha producido una expansión o no.

   set -o noglob

desactivará la expansión en el shell de invocación, pero tendrá que hacerlo antes de invocar su programa.

La alternativa es citar sus argumentos, por ejemplo

foo "*"

4
setopt parece ser un comando específico de zsh. Como dijo otro póster, para bash se usa set -o noglobpara deshabilitar la expansión de comodines.
Wirawan Purwanto

Ahora modificado. Gracias
Brian Agnew

1

Cuidado: si no hay nombres que coincidan con la máscara, bash pasa el argumento tal cual, sin expansión.

Prueba (pa.py es un script muy simple, que solo imprime sus argumentos):

 $ ls
f1.cc  f2.cc  pa.py
 $ ./pa.py *.cc
['./pa.py', 'f1.cc', 'f2.cc']
 $ ./pa.py *.cpp
['./pa.py', '*.cpp']

3
No siempre. set -o nullglobo shopt -s failglob, y este comportamiento cambiará (de dos formas muy diferentes).
Charles Duffy
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.