Enumere todos los directorios que NO tienen un archivo con un nombre de archivo determinado dentro

Enumere todos los directorios que NO tienen un archivo con un nombre de archivo determinado dentro

¿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 findimplementación como GNU findque 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 findcomando:

$ 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, zshpuede hacer esto de forma predeterminada, use set -o globstaren 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 -execopción para findverificar 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.

información relacionada