Liste tous les répertoires qui ne contiennent PAS de fichier portant un nom de fichier donné

11

Comment pourrais-je entrer dans la liste de tous les répertoires qui ne contiennent pas de fichier avec un nom de fichier donné? par exemple, étant donné cet arbre

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

Je veux lister les répertoires qui n'ont pas de fichier nommé README, dans ce cas ce serait le répertoire /c. Comment ferais-je ça? Je ne peux penser à aucune syntaxe utilisant par exemple find.

Renan
la source
Honte, honte, vous n'avez même pas cherché: askubuntu.com/questions/196960/…
slm
Je n'ai probablement pas pensé aux bons mots clés lors de la recherche.
Renan
2
Je suis juste en train de casser tes côtelettes. J'y suis allé plusieurs fois où je ne pouvais pas trouver le bon mot pour rechercher quelque chose 8-).
slm
en relation: askubuntu.com/questions/196960/…
Ciro Santilli 冠状 病毒 审查 六四 事件 法轮功

Réponses:

5

En supposant une findimplémentation comme GNU findqui accepte une {}intégration dans un argument pour -exec:

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

Exemple

Ici, les répertoires 1/1 à 5/5 ont un README, les autres répertoires sont vides.

$ 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

Maintenant, lorsque nous exécutons cette version de notre findcommande:

$ 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

Références

slm
la source
Comment modifier la commande pour rechercher des sous-répertoires qui n'ont pas d'extension de fichier spécifique (disons * .txt). La modification de README avec * .txt ne semble pas fonctionner
WanderingMind
@WanderingMind - si vous avez une nouvelle question, veuillez la poser comme une nouvelle sur le site ;-)
slm
3

Vous pouvez utiliser l' -execoption de findvérifier le fichier, puis imprimer tous les résultats pour lesquels la vérification échoue.

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

Pas besoin de find. Utilisez simplement le shell:

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

Si vous en avez besoin pour être récursif, vous pouvez utiliser (pour bash, zshpeut le faire par défaut, utiliser set -o globstardans ksh93):

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

(notez que les fichiers dot sont exclus par défaut).

terdon
la source
2

Avec zshet qualificatifs glob ( echaîne ):

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

ou

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

ajouter Dpour inclure des répertoires cachés:

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

/sélectionne uniquement les répertoires et e_'[[ ! -f $REPLY/README ]]'_sélectionne uniquement les noms de répertoires pour lesquels le code shell entre les guillemets renvoie true, c'est-à-dire pour chaque nom de répertoire ( $REPLY) vers lequel le glob se *(/)développe, il s'exécute [[ ! -f $REPLY/README ]]et conserve le nom du répertoire si le résultat est true.
La deuxième forme ^e_'.....'_utilise le même qualificatif glob, niée (mais cette fois l'expression conditionnelle n'est pas niée:) [[ -f $REPLY/README ]].


Ce qui précède ne renverra que les noms de répertoire dans le répertoire actuel.
Si vous souhaitez effectuer une recherche récursive (encore une fois, pour inclure les répertoires masqués, ajoutez le Dqualificatif):

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

De manière portable, vous pourriez faire:

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

[ -f file ]teste si le fichier existe et est confirmé comme étant un fichier normal (après la résolution du lien symbolique).

Si vous vouliez tester qu'il existe uniquement (en tant qu'entrée dans ce répertoire), quel que soit son type, vous auriez besoin de:, [ -e file ] || [ -L file ]mais notez que vous avez besoin d'une autorisation de recherche dans le répertoire pour effectuer ces tests. Vous voudrez peut-être ajouter des [ -x "$dir" ]tests pour tenir compte des cas comme:

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 '{}' +

Ou pour éviter les conditions de course, avec 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 '{}' +

Voir aussi Comment savoir si un fichier standard n'existe pas dans Bash? sur SO.

Stéphane Chazelas
la source