Elenca le sottodirectory un livello in basso che non contiene un determinato file

Come posso trovare tutte le sottodirectory in una directory (solo 1 livello in basso) che non contengono un dato file?

Ci sono diversi modi per realizzare questo con la ricerca .

L'approccio 1 è less hacky e funziona bene con nomi di directory sconosciuti (ad esempio, nomi di directory contenenti newlines), ma l'approccio 2 dovrebbe essere più veloce se ci sono molte directory.

Approccio 1

Comando

find DIR -type d -mindepth 1 -maxdepth 1 -not -exec test -f {}/FILENAME \; \ -print | sort 

Come funziona

  • find DIR -type d -mindepth 1 -maxdepth 1 trova tutte le directory ( -type d ) in DIR , con profondità 1.

  • -not -exec test -f {}/FILENAME \; è vero se e solo se un file chiamato FILENAME non è stato trovato nella directory attualmente processata ( {} ).

  • -print emette i nomi di directory desiderati.

  • Se lo si desidera, sort ordinerà l'output in ordine alfabetico.

Approccio 2

Comando

 ( find DIR -type f -mindepth 2 -maxdepth 2 -name FILENAME -printf "%h\n" ; \ find DIR -type d -mindepth 1 -maxdepth 1 ) | sort | uniq -u 

Come funziona

  • find DIR -type f -mindepth 2 -maxdepth 2 -name FILENAME trova tutti i file ( -type f ) chiamati FILENAME nelle sottodirectory di DIR (i file delle directory di profondità 1 hanno profondità 2).

  • -print "%h\n" printingre i nomi delle directory contenenti file denominati FILENAME , seguito da una nuova row.

  • find DIR -type d -mindepth 1 -maxdepth 1 elenca tutte le directory ( -type d ) in DIR , con profondità 1.

  • sort sortisce l'output in ordine alfabetico (l'output deve essere ordinato quando si passa a uniq ).

  • uniq -u printing solo linee uniche.

    Ogni sottodirectory di DIR viene elencata alless una volta, ma quelli che contengono un file chiamato FILENAME vengono elencati due volte. uniq -u elimina il secondo tipo.

Direttamente nello script shell:

 for i in DIRECTORY/*/; do [ -f "$i/FILENAME" ] || basename "$i"; done 
  • for i in DIRECTORY/*/ utilizza l'espansione di shell in modo sicuro (non dovrebbe essere alcun problema con nomi di directory sconosciuti) per tutte le directory secondarie di una directory specifica. Notare la traccia di trailing solo per dare le directory.
  • [ -f "$i/FILENAME" ] restituisce true se il file denominato FILENAME esiste nella directory in questa iterazione. Il || l'operatore esegue il command seguente se il primo viene restituito falso, cioè solo se il file non esiste nella directory.
  • basename "$i" printing il nome della directory (se il nome del file non è stato trovato). Se si desidera il path completo e non solo il nome della directory, sostituire il basename per echo o readlink -f o qualcos'altro per preferenza.

Se si desidera anche includere directory nascoste, eseguire (in Bash)

 shopt -s dotglob 

prima del command.