Con bash, establezca la configuración global para que las coincidencias faltantes no generen un error:
shopt -u failglob # avoid failure report (and discarding the whole line).
shopt -s nullglob # remove (erase) non-matching globs.
ls ?c c?
El signo de interrogación es un carácter global que representa un solo carácter. Como desea nombres de archivo de dos caracteres, uno de ellos debe ser c
, por lo que es el primer carácter o el último carácter.
Con shopt -s dotglob
esto también mostraría un archivo llamado .c
.
Si no hay archivos coincidentes, configurar estas opciones de shell hace que se eliminen todos los argumentos, lo que da como resultado un ls
desnudo -- listando cualquier cosa/todo por defecto.
Usa esto, en su lugar:
shopt -s nullglob ## drop any missing globs
set -- ?c c? ## populate the [email protected] array with (any) matches
if [ $# -gt 0 ] ## if there are some, list them
ls -d "[email protected]"
fi
Creo que la mejor manera es usar find
:
find . -type f -name '*c*' -name '??'
Eso buscará recursivamente. Para enumerar solo los archivos en el directorio actual:
find . ! -name . -prune -type f -name '*c*' -name '??'
Si los archivos existen (y no tienen caracteres de escape como \c
), puedes usar un globo:
echo ?c c?
que coincidirá con los archivos que tienen un carácter (?
) seguido de un c
o que tengan un c
seguido de un carácter (?
).
Pero fallará con los nombres de archivo que comienzan con un guión como -n
o -e
o con caracteres de barra invertida como \c
o \n
con echo
como ambos -e
y -n
son especiales para (algunos proyectiles) echo
y \c
o \n
se interpretaría como una secuencia de escape (\c
finaliza la salida y \n
imprime una nueva línea, no los caracteres textuales \n
en alguna implementación de shell de echo y con bash cuando la opción shopt -s xpg_echo
Está establecido). Otras aplicaciones o utilidades (como ls
) tendrá algunas otras opciones y puede fallar con muchos otros caracteres iniciados por guiones o interpretar otros caracteres de escape en los nombres de archivo.
También mostrará un archivo llamado cc
dos veces.
-
Si un archivo puede comenzar con un guión (como -n), use:
$ ls -d -- ?n -n
O, mejor:
$ ls -d ./?n ./-n
Advertencias
-
Coincidencia global sin archivo.
-
Si los archivos no existen, el globo no se expandirá y se imprimirá en su forma original.
$ echo ?m m? ?m m?
-
Excepto en zsh.
$ zsh -c 'echo ?m m?' zsh:1: no matches found: ./m?
El shell saldrá con un error.
Este comportamiento está controlado pornomatch
de Zsh opción.$ zsh -c 'setopt +o nomatch; echo ?m m?' ?m m?
O:
$ zsh -c 'echo ?m(N) m?(N)' ?m m?
Pero eso imprimirá
mm
dos veces. -
En bash podría obtener un resultado similar a zsh si la opción de shell
failglob
está configurado:$ bash -c 'shopt -s failglob; echo ?m m?' bash: no match: ?m
Pero el script no se detendrá, el shell no se cerrará. Bueno, técnicamente, la línea donde se usa el glob no se ejecuta más, pero la ejecución se reanuda en la siguiente línea de script.
-
En bash puede establecer la opción
nullglob
para eliminar los globos que no coinciden:$ bash -c 'shopt -s nullglob; echo ?m m? done' done
-
-
Usando ls (similar a otros programas)
-
Con archivos coincidentes no habrá problema, pero también coincidirá (y listará) directorios:
$ ls ?c c? bc cz sc ac: hjk
Mejor usa
-d
conls
(los directorios se incluirán pero no se ampliarán).$ ls -d ?c c? ac bc cz sc
-
Globs que no coinciden con un archivo (o un directorio)
Entonces
ls
informará de un error$ ls ?m m? ls: cannot access '?m': No such file or directory
Otros programas podrían (probablemente) no haz comprobaciones similares.
-
Usando
nullglob
con bash le dará una lista vacía a ls, por lo tanto, enumerará los contenidos o el pwd como si solols
fue ejecutado:$ ls ?m m? ac a.out cz 3 b sc ab bc
Eso podría evitarse usando
./
$ ls -d ./?m ./m? ls: cannot access './?m': No such file or directory ls: cannot access './m?': No such file or directory
-
O puede usar una expresión regular de búsqueda (pero atravesará subdirectorios con prune
falta) (Tenga en cuenta que esto no repetirá un archivo llamado cc):
$ find . ! -name . -prune -regex '.*/\(.c\|c.\)'
./ac
./cc
./sc
./bc
./cz