web-dev-qa-db-fra.com

Nom du premier fichier dans le répertoire obtenu de manière optimale

Ordinaire quand je veux montrer le nom du premier fichier du répertoire que je tape:

ls raw/all | head -n 1

Mais cela prend du temps quand dans le répertoire il y a beaucoup de fichiers


Par exemple, pour dir avec près de 900 k fichiers, nous avons les mesures suivantes:

time ls raw/all | head -n 1 

real    0m17.250s | 0m10.328s | 0m6.334s
user    0m3.224s  | 0m3.884s  | 0m3.192s
sys     0m0.544s  | 0m0.664s  | 0m0.572s

la boucle While sur tous les fichiers prend:

time ls raw/all | wc -l

real    0m6.455s | 0m5.869s  | 0m5.228s
user    0m3.612s | 0m3.468s  | 0m4.072s
sys     0m0.460s | 0m0.784s  | 0m0.624s

Comment imprimer le nom du premier fichier de manière efficace?

1
Daniel

C'est délicat. Deux approches:


approche 1; find:

find . -mindepth 1 -print -quit

find et -prints le premier fichier trouvé et -quits immédiatement. -mindepth 1 empêchera de faire correspondre le . lien dur du répertoire en cours.

Si vous êtes intéressé uniquement par les fichiers ordinaires, ajoutez -type f:

find . -type f  -print -quit

-mindepth 1 peut être supprimé alors que . étant un répertoire ne correspond pas.


Approche 2; sh, stdbuf et awk:

Notez que ARG_MAX peut être déclenché pour un trop grand nombre de fichiers (la liste des arguments devenant trop longue, sur ARG_MAX octets). Dans ce cas, utilisez l'approche 1.

  • n'importe quel shell shell (par exemple printf, echo) pour imprimer le nom de fichier
  • Shell globbing, *, pour effectuer le développement (l'ordre de classement doit être identique à ls pour un locale 'LC_COLLATE donné)
  • stdbuf -o0 (stdbuf est fourni avec GNU coreutils) pour que le flux STDOUT de printf/echo soit sans tampon
  • pipe (|) le STDOUT de printf/echo à awk et exit après avoir imprimé le premier enregistrement
  • Après la sortie de awk, stdbuf (printf) recevrait SIGPIPE et serait tué.
  • J'utiliserais printf pour obtenir les noms de fichiers séparés par ASCII NUL (\0) et utiliser \0 comme séparateur d'enregistrement dans awk pour traiter tous les cas Edge, dans la mesure où les noms de fichiers sont concerné

Mettre ensemble ces:

stdbuf -o0 printf '%s\0' * | awk 'BEGIN{RS="\0"} {print;  exit}'
2
heemayl