Sustitución de command en for loop no funciona

Quiero mantener todos los files que no terminan con .bat

Lo intenté

 for f in $(ls | egrep -v .bat); do echo $f; done 

y

 for f in $(eval ls | egrep -v .bat); do echo $f; done 

Pero ambos enfoques arrojan el mismo resultado, ya que imprimen todo. Considerando que ls | egrep -v .bat ls | egrep -v .bat y eval ls | egrep -v .bat eval ls | egrep -v .bat work per se, si se usa aparte del ciclo for .

EDITAR

Es interesante ver que si dejo fuera el indicador -v , el ciclo hace lo que debería y se enumeran todos los files que terminan en .bat .


Siéntase libre de editar el título de la pregunta, ya que no estaba seguro de cuál es el problema.

Estoy usando GNU bash, version 4.1.10(4)-release (i686-pc-cygwin).


EJEMPLO

 $ ls -l | egrep -v ".bat" total 60K -rwx------+ 1 SYSTEM SYSTEM 5.3K Jun 6 20:31 fsc* -rwx------+ 1 SYSTEM SYSTEM 5.3K Jun 6 20:31 scala* -rwx------+ 1 SYSTEM SYSTEM 5.3K Jun 6 20:31 scalac* -rwx------+ 1 SYSTEM SYSTEM 5.3K Jun 6 20:31 scaladoc* -rwx------+ 1 SYSTEM SYSTEM 5.3K Jun 6 20:31 scalap* 

El command está funcionando, pero no en el ciclo for.

 $ for f in $(ls | egrep -v .bat); do echo $f; done fsc fsc.bat scala scala.bat scalac scalac.bat scaladoc scaladoc.bat scalap scalap.bat scalac scalac.bat scaladoc scaladoc.bat scalap scalap.bat 

DEBUG $ set -x

 mike@pc /cygdrive/c/Program Files (x86)/scala/bin $ for f in $(ls | egrep -v .bat); do echo $f; done ++ ls -hF --color=tty ++ egrep --color=auto -v .bat + for f in '$(ls | egrep -v .bat)' + echo fsc fsc + for f in '$(ls | egrep -v .bat)' + echo fsc.bat fsc.bat // and so on 

Algunas cosas mal en tu código:

Usar la sustitución de command sin comillas ( $(...) ) sin establecer $IFS

Dejando expansiones sin comillas es el operador split + glob. El valor pnetworkingeterminado es dividir en espacio, pestaña y nueva línea. Aquí, solo quiere dividir en línea nueva, por lo que debe configurar IFS para eso, ya que de lo contrario eso significa que no funcionará correctamente si los nombres de file contienen espacios o tabuladores

Usar sustitución de command sin comillas sin set -f .

Dejando expansiones sin comillas es el operador split + glob. Aquí no desea globbing, es la expansión de comodines como scala* en la list de files coincidentes. Cuando no quiere que el shell haga globbing, tiene que deshabilitarlo con set -f

Aliased a ls -F

El problema anterior se ve agravado por el hecho de que tiene ls aliased a ls -F . Que agrega / a directorys y * a files ejecutables. Entonces, típicamente, debido a que scala es ejecutable, ls -F genera scala* , y como un patrón globbing, se expande a todos los nombres de file que comienzan con scala que explica por qué parece que egrep -v no está filtrando los files.

Asumiendo que los nombres de file no contengan caracteres de nueva línea

newline es un personaje tan válido como cualquier otro en un nombre de file. Entonces, analizar la salida de ls normalmente no funciona . Por ejemplo, la salida de ls en un directory que contiene files a y b es la misma que en un directory que contiene un file llamado a\nb .

Por encima de egrep filtrará las líneas de los nombres de file, no los nombres de file

Usando egrep lugar de grep -E

egrep está en desuso. grep -E es el equivalente estándar.

No escapando del . operador de expresiones regulares

Arriba, egrep para habilitar expresiones regulares extendidas , pero no usas ninguno de los operadores específicos RE extendidos. El único operador de RE que estás usando es . para unir cualquier personaje, aunque parezca que no es lo que pretendías. Así que bien podrías haber usado grep -F aquí. O use grep -v '\.bat' .

No anclando la expresión regular al final de línea

egrep .bat coincidirá con cualquier línea que contenga cualquier carácter seguido de un bat , por lo que esa es la expresión regular que significa cualquier cosa que contenga un bat no esté en la primera position. Debería haber sido grep -v '\.bat$' .

Dejar $f comillas

Dejando una expansión sin comillas es el operador split + glob. Allí, usted tampoco quiere, por lo que $f debe ser citado ( "$f" ).

Usa echo

echo expande las secuencias de escape ANSI C en sus arguments y / o trata cadenas como -n o -e especialmente según la implementación del echo (y / o el entorno).

Use printf lugar .

Entonces una mejor solución:

 for f in *; do case $f in (*.bat);; (*) printf '%s\n' "$f" esac done 

Aunque si no hay un file no oculto en el directory actual, eso seguirá generando * . Puede shopt -s nullglob esto en zsh cambiando * a *(N) o en bash ejecutando shopt -s nullglob .

No debe usar ls para analizar files de esta manera.

Primero establezca extglob globstar por shopt -s extglob globstar luego

 for f in !(*.bat) do printf '%s\n' "$f" done 

Usando find

 find . -type f ! -name '*.bat' 

Use el operador de negación para un tratamiento más seguro de los files.

No hay nada intrínsecamente incorrecto con su bucle for:

 $ for f in $(ls | egrep -v .bat); do echo $f; done 

Aquí está mi salida para el command anterior:

 $ for f in $(ls | egrep -v .bat); do echo $f; done fsc scala scalac scaladoc scalap 

Posible solución

Una sugerencia sería citar el argumento a egrep , así:

 $ for f in $(ls | egrep -v '.bat'); do echo $f; done 

También eche un vistazo a la wiki de Bash Pitfalls para otros posibles problemas al crear guiones en Bash como este. En particular, esto parece ser la razón más plausible por la que estás encontrando este problema. Verifique si alguno de sus files devueltos contiene espacios.

Depuración

Otra cosa que debes probar es habilitar la debugging detallada de tu command bash, antes de ejecutarlo para que puedas ver lo que ocurre detrás de las escenas.

Esto permite la debugging:

 $ set -x 

Luego ejecuta tu command:

 $ for f in $(ls | egrep -v .bat); do echo $f; done ++ ls --color=auto ++ egrep --color=auto -v .bat + for f in '$(ls | egrep -v .bat)' + echo fsc fsc + for f in '$(ls | egrep -v .bat)' + echo scala scala + for f in '$(ls | egrep -v .bat)' + echo scalac scalac + for f in '$(ls | egrep -v .bat)' + echo scaladoc scaladoc + for f in '$(ls | egrep -v .bat)' + echo scalap scalap 

Luego deshabilítelo:

 $ set +x 

¿Problema con Cygwin?

Dado que los ejemplos funcionan bien en una serie de sistemas Linux nativos, el problema probablemente esté enraizado en tener algo que ver con Cygwin y / o sus versiones particulares de bash y egrep . Prestaré particular atención al separador de campo en Bash, $IFS para ver si hay un problema entre los diversos separadores de línea en Windows ( 0x0d,0x0a ) frente a Unix ( 0x0a ).

No tengo una installation de Cygwin, así que no tengo ningún método para probar esta hipótesis.