Devolver selectivamente la lista de archivos
Contexto: OSX Catalina (zSh) y Ubuntu 16.04 (Bash). Comandos de terminal OSX:
FILES="$PWD/*" #list of files
echo $FILES
devuelve una cadena de todos los archivos a la consola. Por ahora, tengo la intención de sembrar una copia del script en el directorio que se procesará. En el futuro, espero habilitar el script para aceptar un argumento (directorio) para ser procesado.
Suponga que los tipos de archivo (extensiones y no archivos ocultos) están presentes en el directorio de trabajo:
- .a B C
- .A B C
- .def
- .ghi
- .jkl
- .sh
Estoy interesado en ejemplos modificados de las instrucciones anteriores que:
- seleccione explícitamente solo .abc .ABC y .def tipos de archivo (extensiones)
- seleccione todos los archivos excepto .sh y .jkl
Idealmente, habría una opción de comando para especificar mayúsculas y minúsculas
Respuestas
Puede hacer esto con bastante facilidad usando matrices en bash (que es el shell predeterminado en Ubuntu, macOS es bash o zsh para las versiones más nuevas; estas soluciones son sobre bash):
Seleccione todos los archivos (su comando original, ligeramente modificado):
$ shopt -s nullglob $ files=(*) $ echo "${files[@]}" file.abc file.ABC file.def file.ghi file.jkl file.shActivar la
nullglobopción da una lista vacía si el directorio está vacío. Sin esta opción, si el directorio estuviera vacío,filessería una lista de un elemento que no está expandido*.Seleccione solo aquellos archivos cuyos nombres terminen en
.abco.ABCo.def:$ shopt -s nullglob $ files=(*.abc *.ABC *.def) $ echo "${files[@]}" file.abc file.ABC file.defSeleccione todos los archivos excepto aquellos cuyos nombres terminen en
.sho.jkl$ shopt -s extglob nullglob $ files=(!(*.sh|*.jkl)) $ echo "${files[@]}" file.abc file.ABC file.def file.ghiCoincidencia que no distingue entre mayúsculas y minúsculas
$ shopt -s nocaseglob nullglob $ files=(*abc) $ echo "${files[@]}" file.abc file.ABC
Además, una nota sobre lo que estaba haciendo. files="$PWD/*"no establece el valor de $filesa todos los archivos en su directorio actual. Establece su valor en una cadena que termina en /*:
$ cd /tmp/current_directory
$ files="$PWD/*"
$ echo "$files"
/tmp/current_directory/*
La razón por la que pensó que funcionaba fue porque estaba usando sin echo $filescomillas, lo que significa que el shell se estaba expandiendo /tmp/current_directory/*. Sin embargo, si luego eliminara los archivos, el mismo echocomando simplemente se imprimiría /tmp/current_directory/*con $PWDexpandido en cualquier directorio en el que haya ejecutado esto originalmente. La lista de archivos no se guardaría con la variable. Usar las matrices como lo hice aquí garantiza que la variable almacene la lista real de archivos y no solo el elemento global que se puede expandir a diferentes valores dependiendo de dónde lo use.
En zsh:
files=($PWD/*.(abc|ABC|DEF)(N))
print -rC1 -- $files # print raw, on one column.
(con el (N)calificador para aplicar nullgloba ese glob, que se $filesconvierta en una lista vacía del patrón no coincide con ningún archivo en lugar de informar un error).
Para archivos que no sean .shy .jkl:
set -o extendedglob # needed for the ^ negation operator
files=($PWD/^*.(sh|jkl)(N))
Para coincidencias que no distinguen entre mayúsculas y minúsculas ( .ABC/ .abc/ .Abc...):
set -o extendedglob
files=($PWD/*.(#i)abc(N))
Tu:
FILES="$PWD/*"
echo $FILES
está mal en varias cuentas:
FILES="$PWD/*"no almacena la lista de archivos en la $FILEvariable. Esa es una asignación escalar, que solo puede almacenar un valor. En su lugar, almacena $FILESel contenido de $PWDseguido de /*literalmente.
En, echo $FILEScomo $FILESno se cita, en bash(pero no zsh), la expansión de $FILESestá sujeta a split + glob. Y es en ese punto, y asumiendo que $FILESno contiene ninguno de los caracteres de $IFS(lo que desencadenaría la parte dividida ) y que $PWDno contiene caracteres comodín (que también desencadenarían la parte glob) que el valor se expande a la lista de archivos coincidentes.
In zsh, split+glob is not done implicitly upon parameter expansion, you need to request them explicitly ($=FILES for splitting, $~FILES for globbing, $=~FILES for both).
Then using echo to output arbitrary data is wrong as echo does extra processing by default (in zsh, you could use echo -E - $files or print -r -- $files though).