¿Cómo puedo evitar que la expansión de Bash pase archivos que comienzan con "-" como argumento?

14

Estoy tratando de buscar recursivamente una cadena con greppero obtengo esto:

$ grep -r "stuff" *
grep: unrecognized option '---corporate-discount.csv'
Usage: grep [OPTION]... PATTERN [FILE]...
Try 'grep --help' for more information.

¿Cómo puedo evitar que Bash pase archivos que comienzan -como argumento?

Chef Tony
fuente
3
Realmente no quieres evitar que el shell pase estos archivos, ¿verdad? La pregunta es más bien cómo saber grepque no son opciones.
DonHolgo
11
... para ser claros, bash no controla qué resultados se tratan como opciones frente a los tratados como argumentos; eso está en el control del programa receptor. Obtendría el mismo comportamiento con, por ejemplo, subprocess.Popen(['grep', '-r', '-e' 'stuff', '--corporate-discount.csv'])en Python, no bash en ningún lado.
Charles Duffy
1
Lectura relacionada: Unix Wildcards Gone Wild , sobre problemas de seguridad que pueden ser causados ​​por el uso *de comandos. TODOS estos se pueden evitar utilizando en su ./*lugar.
Comodín
1
@Wildcard, el uso --como sigil de fin de opciones también es perfectamente razonable; Las pautas de sintaxis de la utilidad POSIX requieren que se respete; ver directriz # 10. (Claro, no todos los programas siguen las pautas POSIX, pero la respuesta es encadenar a los autores de los programas infractores y / o expulsarlos de la industria).
Charles Duffy

Respuestas:

43

Primero, tenga en cuenta que la interpretación de los argumentos que comienzan con guiones depende del programa que se inicie grepu otro. El shell no tiene forma directa de controlarlo.

Suponiendo que desea procesar dichos archivos (y no ignorarlos por completo) grep, junto con la mayoría de los programas, reconoce --que indica el final de las opciones, por lo que

grep -r -e "stuff" -- *

Hará lo que quieras. El -eestá allí en caso de que stuffcomience con un -también.

Alternativamente, también puedes usar:

grep -r -e "stuff"  ./*

Este último también evitaría el problema si hubiera un archivo llamado -en el directorio actual. Incluso después del --separador, grepinterpreta -como significado stdin, mientras ./-que el archivo se llama -en el directorio actual.

Ícaro
fuente
8

Para evitar que la expansión Bash pase archivos que comienzan con “-” , puede usar:

echo [!-]*

Que funciona de forma portátil en la mayoría de los shells, o, específicamente para ksh, bash, zsh:

echo !(-*)

Por ejemplo: en un directorio con estos archivos

$ echo *
a b c ---corporate-discount.csv d -e --option.txt

Solo se enumerará (siempre que extglobesté activo):

$ shopt -s extglob
$ echo !(-*)
a b c d

$ echo [!-]*
a b c d

Pero si lo que desea es procesar todos los archivos mientras le dice a grep que evite interpretar los archivos indicados con una -opción como, entonces simplemente agregue un ./:

grep -r "stuff" ./*

O bien, si existe la garantía de que no existe un archivo llamado exactamente -en los archivos enumerados (grep interpretará un solo -como leído desde stdin ), puede usar:

grep -r -- "stuff" *
Isaac
fuente
Sí, como la pregunta es sobre bash, un shell de GNU, parece razonable suponer que un grep de GNU está disponible, podría instalarse o realmente se está utilizando. @ StéphaneChazelas
Isaac
Sí, a grep -r -- stuff *es más simple y también funciona con greps no GNUish. Entonces: agregado, gracias. @ StéphaneChazelas
Isaac
@ Isaac No diría que es una suposición razonable "si bash está disponible, GNU grep también está disponible". Tomemos por ejemplo FreeBSD: bash no está instalado de manera predeterminada , que se puede instalar más tarde, pero no tiene ningún efecto en grep: sigue siendo la versión BSD de grep a menos que GNU grep esté explícitamente instalado. Pero eso es un pequeño detalle. Me gusta el enfoque alternativo a través de extglob, por lo tanto, hice +1 en la respuesta
Sergiy Kolodyazhnyy
2
@SergiyKolodyazhnyy, AFAIK, grepen FreeBSD todavía se basa en GNU grepy todavía tiene esa característica errónea de que las opciones se reconocen después de no opciones. Incluso los BSD como OpenBSD que han reescrito los han grephecho compatibles con GNU para la portabilidad hacia atrás (y aún muestran ese comportamiento aquí). En macOS, sh es bash, pero espero que su grep no muestre ese comportamiento ya que macOS debe cumplir con POSIX incluso sin $ POSIXLY_CORRECT. En cualquier caso, el grep del OP es compatible con GNU ya que da ese error.
Stéphane Chazelas
1
Ver también echo [!-]*como un equivalente estándar de ksh's (o bash -O extglob's) echo !(-*).
Stéphane Chazelas