Pourquoi find -exec du résumé différemment?

J'ai des photos de famille et des films dans un dossier / media / data / Selbstgemacht et j'aimerais find la taille de toutes les photos. Dans / media / data j'utilise find Selbstgemacht -type f -iname '*.jpg' -exec du -ch '{}' + qui renvoie 5,1 Go.
Cependant, si je descend dans le dossier "Selbstgemacht" et utilise find . -type f -iname '*.jpg' -exec du -ch '{}' + find . -type f -iname '*.jpg' -exec du -ch '{}' + il renvoie 7,0 Go.

J'ai ensuite comparé la sortie de find pour vérifier s'ils trouvent les mêmes files:
Dans le dossier parent, select find Selbstgemacht -type f -iname '*.jpg' -printf '%P\n' |sort > test1.txt
De la find . -type f -iname '*.jpg' -printf '%P\n' |sort > ../test2.txt sous-dossier find . -type f -iname '*.jpg' -printf '%P\n' |sort > ../test2.txt find . -type f -iname '*.jpg' -printf '%P\n' |sort > ../test2.txt

Les files sont identiques, donc les deux trouvent des commands qui trouvent exactement les mêmes files, ce qui m'amène à penser que la différence dans la taille du rapport doit être due à autre chose.

Quelle est exactement la cause ici?

Informations système:

  • L'écurie Debian
  • find (GNU findutils) 4.4.2
    • D_TYPE O_NOFOLLOW (activé)
    • LEAF_OPTIMISATION, FTS (), CBO (niveau = 0)
  • du (GNU coreutils) 8.13

find ... -exec cmd {} + exécutera cmd autant de fois que nécessaire afin de ne pas dépasser la limite de la taille des arguments transmis à une command.

Lorsque vous utilisez find . -exec du {} + find . -exec du {} + , la taille de la list des files est plus petite que lors de l'utilisation de find verylongdirname -exec du {} + .

Il est donc probable que la fonction find verylongdirname exécute plus de commands que la find . un. Le total que vous voyez à la fin est le total de la dernière exécution du du , qui n'inclut pas tous les files (il y aura eu plus de totaux plus tôt, vous pouvez envoyer la command à grep 'total$' pour confirmer.

Ce que vous devriez voir est que dans les deux cas, vous n'obtenez probablement pas l'utilisation de l'espace disque de vos images. Si vous avez des milliers d'images, il est probable que dans les deux cas cela dépasse la limite pour l'appel exec.

Pourquoi? Eh bien, la command -exec (...) + ajoute des parameters à l' execvp système execvp . La page man définit la limite de son appel système sous-jacent comme suit (extrait de la page de manuel execve ):

 Limits on size of arguments and environment Most UNIX implementations impose some limit on the total size of the command-line argument (argv) and environment (envp) ssortingngs that may be passed to a new program. (...) On kernel 2.6.23 and later, most architectures support a size limit derived from the soft RLIMIT_STACK resource limit (see getrlimit(2)) that is in force at the time of the execve() call. (...) This change allows programs to have a much larger argument and/or environment list. For these architectures, the total size is limited to 1/4 of the allowed stack size. (...) Since Linux 2.6.25, the kernel places a floor of 32 pages on this size limit, so that, even when RLIMIT_STACK is set very low, applications are guaranteed to have at least as much argument and environment space as was provided by Linux 2.6.23 and earlier (This guarantee was not provided in Linux 2.6.23 and 2.6.24.) Additionally, the limit per ssortingng is 32 pages (the kernel constant MAX_ARG_STRLEN), and the maximum number of ssortingngs is 0x7FFFFFFF. 

Donc, si vous avez une longue list de files, vous pouvez rapidement atteindre les limites du système. En outre, lorsque le path relatif est plus long, il utilise plus de memory qui peut triggersr que vous atteignez les limites plus rapidement, d'où les différents résultats de vos 2 commands.

Il y a une solution

Une solution sur les systèmes GNU est d'utiliser une list de files en input pour utiliser les options --files0-from . Avec votre exemple:

 find Selbstgemacht -type f -iname '*.jpg' -print0 | du --files0-from=- -ch 

La première command répertorie tous les files et les produit sur la sortie standard séparée par NUL ( \0 ). Cette list est ensuite "ingérée" par le du input standard (le - nom du file) et de résumer le total.