Elencare tutte le directory che NON hanno un file con un nome file all'interno


11

Come potrei elencare tutte le directory che non hanno un file con un nome di file all'interno? ad esempio dato questo albero

/
  /a
     README
     file001
     file002
  /b
     README
     file001
  /c
     file003

Voglio elencare le directory che non hanno un file chiamato README, in questo caso sarebbe directory /c. Come potrei farlo? Non riesco a pensare a nessuna sintassi usando ad es find.


Peccato oh vergogna che non hai nemmeno cercato: askubuntu.com/questions/196960/…
slm

Probabilmente non ho pensato alle parole chiave giuste durante la ricerca.
Renan

2
Ti sto solo spezzando le costolette. Ci sono stato molte volte in cui non riuscivo a pensare alla parola giusta per cercare qualcosa Cool.
SLM

Risposte:


5

Supponendo findun'implementazione come GNU findche accetta un {}incorporato in un argomento per -exec:

$ find . -type d \! -exec test -e '{}/README' \; -print

Esempio

Qui le directory da 1/1 a 5/5 hanno un README, le altre directory sono vuote.

$ 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

Ora quando eseguiamo questa versione del nostro 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

Riferimenti


Come modificare il comando per cercare sottodirectory che non hanno un'estensione di file specifica (ad esempio * .txt). La modifica di README con * .txt non sembra funzionare
WanderingMind

@WanderingMind - se hai una nuova domanda, per favore, ponila come nuova sul sito ;-)
slm

3

È possibile utilizzare l' -execopzione di findper verificare il file, quindi stampare tutti i risultati per i quali il controllo ha esito negativo.

find /path/to/base -mindepth 1 -maxdepth 1 -type d -exec test -e {}/README \; -o -print

3

Non c'è bisogno di find. Basta usare la shell:

for d in */; do [ -f "$d"README ] || printf '%s\n' "$d"; done
c/

Se è necessario che sia ricorsivo, è possibile utilizzare (poiché bash, zshper impostazione predefinita, utilizzare set -o globstarin ksh93):

shopt -s globstar
for d in **/; do [ -f "$d"README ] || printf '%s\n' "$d"; done

(nota che i file di punti sono esclusi per impostazione predefinita).


2

Con zshe qualificatori glob ( estringa ):

print -rl -- *(/e_'[[ ! -f $REPLY/README ]]'_)

o

print -rl -- *(/^e_'[[ -f $REPLY/README ]]'_)

aggiungi Dper includere directory nascoste:

print -rl -- *(D/e_'[[ ! -f $REPLY/README ]]'_)

/seleziona solo le directory e e_'[[ ! -f $REPLY/README ]]'_seleziona ulteriormente solo i nomi delle directory per cui restituisce il codice della shell tra virgolette true, ovvero per ogni nome di directory ( $REPLY) a cui si *(/)espande il glob , viene eseguito [[ ! -f $REPLY/README ]]e mantiene il nome della directory se il risultato è true.
Il secondo modulo ^e_'.....'_utilizza lo stesso qualificatore glob, negato (ma questa volta l'espressione condizionale non viene negata:) [[ -f $REPLY/README ]].


Quanto sopra restituirà solo i nomi delle directory nella directory corrente.
Se vuoi cercare ricorsivamente (di nuovo, per includere le directory nascoste aggiungi il Dqualificatore):

print -rl ./**/*(/e_'[[ ! -f $REPLY/README ]]'_)

2

Portabilmente, potresti fare:

find . -type d -exec sh -c '
  for dir do
    [ -f "$dir/README" ] || printf "%s\n" "$dir"
  done' sh '{}' +

[ -f file ]verifica se il file esiste ed è confermato come file normale (dopo la risoluzione del collegamento simbolico).

Se si desidera verificare che esiste solo (come voce in quella directory), indipendentemente dal tipo, è necessario:, [ -e file ] || [ -L file ]tuttavia, è necessario disporre dell'autorizzazione di ricerca nella directory per eseguire tali test. Potresti voler aggiungere alcuni [ -x "$dir" ]test per tenere conto di quei casi come:

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 per evitare le condizioni di gara, 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 '{}' +

Vedi anche Come posso sapere se un file normale non esiste in Bash? su SO.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.