Estoy usando el ls
comando en bash, tratando de encontrar todos los archivos o directorios de longitud n. digamos n=5
Mi comando es:
ls ?????
Pero esto también incluiría caracteres que no sean letras, como el punto. Por ejemplo, los siguientes archivos coincidirían:
ab.cd
abd.c
Solo quiero hacer coincidir archivos que tengan nombres de 5 letras o números:
five1
five2
five3
Pero no
abc.d
ab.cd
a.bcd
¿Cómo puedo modificar mi comando?
Respuesta encontrada:
ls [a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9]
Encontré la respuesta, pero ¿cómo puedo hacer que esto sea menos feo?
Respuesta1
Tenga en cuenta que no es eso ls
lo que interpreta esos globos. Su shell expande esos globos en una lista de nombres de archivos que se pasa como argumentos a ls
. Diferentes proyectiles tienen diferentes capacidades de globo. bash
tiene algunas extensiones sobre los globos estándar (tomados prestados ksh88
y habilitados con shopt -s extglob
) pero aún es limitado en comparación con shells como zsh
o ksh93
.
Con zsh
:
setopt extendedglob
ls -d [[:alnum:]](#c5)
ksh93
:
ls -d {5}([[:alnum:]])
o:
ls -d {5}(\w) # (\w includes underscore in addition to alnums)
o, si desea utilizar expresiones regulares extendidas:
ls -d ~(E)^[[:alnum:]]{5}$
Con bash
u otros shells POSIX que no tengan operadores globales equivalentes, deberá hacer:
ls -d [[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]]
Tenga en cuenta que [[:alnum:]]
incluye cualquier carácter alfabético en la configuración regional actual (no solo los alfabetos latinos y mucho menos el inglés) y 0123456789
(y posiblemente otros tipos de dígitos). Si desea las letras del alfabeto inglés, nombre los caracteres individualmente:
c='[0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]'
unset -v IFS
ls -d $c$c$c$c$c
O use la configuración regional C:
(export LC_ALL=C
ls -d [[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]])
Respuesta2
ls -q | grep -Ex '[[:alnum:]]{5}'
Respuesta3
Si vas a utilizar ls
la forma que mencionaste, debes usar la -d
opción; de lo contrario, enumerará elcontenidode cualquierdirectorios
cuyos nombres tienen cinco letras y/o dígitos, en lugar de enumerar los nombres mismos. Además, puedes hacer
ls -d [[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]]
pero eso es exactamente lo mismo que escribir la respuesta que tienes ahora.
Además, si no lo hacesnecesidadpara usar ls
en tu comando, puedes usar
echo [[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]]
que enumerará todas las coincidencias en una línea, o
printf "%s\n" [[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][:alnum:]]
que los enumerará en líneas separadas.
Respuesta4
Construya la expresión en una variable:
e=""; for m in $(seq 1 5); do e="$e[A-Za-z0-9]"; done
Ponlo en una función para que sea elegante/reutilizable:
alnumglob() {
local e=""
for m in $(seq 1 $1) ; do e="$e[A-Za-z0-9]"; done
echo "$e"
}
ls -ld $(alnumglob 5)