
¿Cómo puedo enumerar todos los directorios que lo hacen?no¿Tiene un archivo con un nombre de archivo determinado dentro? por ejemplo, dado este árbol
/
/a
README
file001
file002
/b
README
file001
/c
file003
Quiero enumerar los directorios que lo hacen.notener un archivo llamado README
, en este caso sería directorio /c
. ¿Como podría hacerlo? No se me ocurre ninguna sintaxis que utilice, por ejemplo find
, .
Respuesta1
Suponiendo una find
implementación como GNU find
que acepta un {}
argumento incrustado para -exec
:
$ find . -type d \! -exec test -e '{}/README' \; -print
o, sin la problemática incrustación:
$ find . -type d ! -exec sh -c 'test -e "$1"/README' sh {} \; -print
Ejemplo
Aquí los directorios 1/1 al 5/5 tienen un archivo README, los otros directorios están vacíos.
$ tree
.
|-- 1
| `-- 1
| `-- README
|-- 10
| `-- 10
|-- 2
| `-- 2
| `-- README
|-- 3
| `-- 3
| `-- README
|-- 4
| `-- 4
| `-- README
|-- 5
| `-- 5
| `-- README
|-- 6
| `-- 6
|-- 7
| `-- 7
|-- 8
| `-- 8
`-- 9
`-- 9
Ahora, cuando ejecutamos esta versión de nuestro find
comando:
$ find . -type d \! -exec test -e '{}/README' \; -print
.
./10
./10/10
./7
./7/7
./9
./9/9
./6
./6/6
./5
./8
./8/8
./4
./1
./3
./2
Referencias
Respuesta2
No es necesario find
. Solo usa el shell:
for d in */; do [ -f "$d"README ] || printf '%s\n' "$d"; done
c/
Si necesita que sea recursivo, puede usar (para bash
, zsh
puede hacer esto de forma predeterminada, use set -o globstar
en ksh93
):
shopt -s globstar
for d in **/; do [ -f "$d"README ] || printf '%s\n' "$d"; done
(tenga en cuenta que los archivos de puntos están excluidos de forma predeterminada).
Respuesta3
Puede usar la -exec
opción para find
verificar el archivo y luego imprimir todos los resultados en los que falla la verificación.
find /path/to/base -mindepth 1 -maxdepth 1 -type d -exec test -e {}/README \; -o -print
Respuesta4
De forma portátil, podrías hacer:
find . -type d -exec sh -c '
for dir do
[ -f "$dir/README" ] || printf "%s\n" "$dir"
done' sh '{}' +
[ -f file ]
prueba si el archivoexiste ySe confirma que es un archivo normal (después de la resolución del enlace simbólico).
Si quisiera probar que existe únicamente (como una entrada en ese directorio), independientemente de su tipo, necesitaría: [ -e file ] || [ -L file ]
, aunque tenga en cuenta que necesita permiso de búsqueda en el directorio para realizar esas pruebas. Es posible que desee agregar algunas [ -x "$dir" ]
pruebas para tener en cuenta casos como:
find . -type d -exec sh -c '
for dir do
if [ -x "$dir" ]; then
[ -f "$dir/README" ] || printf "%s\n" "$dir"
else
printf >&2 "Cannot tell for \"%s\"\n" "$dir"
fi
done' sh '{}' +
O para evitar la condición de carrera, con zsh
:
find . -type d -exec zsh -c '
zmodload zsh/system
for dir do
ERRNO=0
if [ ! -f "$dir/README" ]; then
if [ "$errnos[ERRNO]" = ENOENT ]; then
printf "%s\n" "$dir"
else
syserror -p "ERROR: $dir/README: "
fi
fi
done' zsh '{}' +
Ver también¿Cómo puedo saber si un archivo normal no existe en Bash?en lo.