J'utilise find pour tous les fichiers du répertoire, donc j'obtiens une liste de chemins. Cependant, je n'ai besoin que de noms de fichiers. c'est-à-dire que je reçois ./dir1/dir2/file.txt
et je veux obtenirfile.txt
266
Dans GNU, find
vous pouvez utiliser des -printf
paramètres pour cela, par exemple:
find /dir1 -type f -printf "%f\n"
-o
a une priorité inférieure à celle implicite-a
, vous voudrez donc souvent regrouper vos-o
arguments)Si votre recherche n'a pas d'option -printf, vous pouvez également utiliser le nom de base:
la source
... {} ';'
Utilisation
-execdir
qui contient automatiquement le fichier actuel{}
, par exemple:Vous pouvez également utiliser
$PWD
au lieu de.
(sur certains systèmes, il ne produira pas de point supplémentaire à l'avant).Si vous avez encore un point supplémentaire, vous pouvez également exécuter:
Lorsqu'il est utilisé à la
+
place de;
, alors{}
est remplacé par autant de chemins que possible pour chaque invocation d'utilitaire. En d'autres termes, il imprimera tous les noms de fichiers sur une seule ligne.la source
./filename
au lieu defilename
. Selon vos besoins, cela peut ou peut ne pas être bien.$PWD
au lieu de.
.Si vous utilisez GNU find
Ou vous pouvez utiliser un langage de programmation tel que Ruby (1.9+)
Si vous avez envie d'une solution bash (au moins 4)
la source
Si vous souhaitez exécuter une action uniquement contre le nom de fichier, utilisez
basename
peut être difficile.Par exemple ceci:
fera simplement écho au nom de base
/my/found/path
. Pas ce que nous voulons si nous voulons exécuter sur le nom de fichier.Mais vous pouvez ensuite
xargs
la sortie. par exemple pour tuer les fichiers dans un répertoire basé sur des noms dans un autre répertoire:la source
find ~/clang+llvm-3.3/bin/ -type f -exec basename {} \;
Sur Mac (BSD
find
) utilisez:la source
-exec
et-execdir
sont lents,xargs
est roi.xargs
Le parallélisme aide également.Curieusement, je ne peux pas expliquer le dernier cas de
xargs
sans-n1
. Il donne le résultat correct et c'est le plus rapide¯\_(ツ)_/¯
(
basename
prend seulement 1 argument de chemin maisxargs
les enverra tous (en fait 5000) sans-n1
. ne fonctionne pas sur linux et openbsd, seulement macOS ...)Quelques chiffres plus importants d'un système Linux pour voir comment cela
-execdir
aide, mais toujours beaucoup plus lentement qu'un parallèlexargs
:la source
find
c'est-execdir
celui qui devient le plus rapide car la création de nouveaux processus est une opération relativement coûteuse.Honnêtement
basename
, lesdirname
solutions sont plus faciles, mais vous pouvez également vérifier ceci:ou
ou
la source
Comme d'autres l'ont souligné, vous pouvez combiner
find
etbasename
, mais par défaut, lebasename
programme ne fonctionnera que sur un chemin à la fois, donc l'exécutable devra être lancé une fois pour chaque chemin (en utilisant l'unfind ... -exec
ou l' autrefind ... | xargs -n 1
), ce qui peut potentiellement être lent.Si vous utilisez l'
-a
option onbasename
, elle peut accepter plusieurs noms de fichiers en une seule invocation, ce qui signifie que vous pouvez ensuite utiliserxargs
sans le-n 1
, pour regrouper les chemins d'accès en un nombre beaucoup plus faible d'invocations debasename
, ce qui devrait être plus efficace.Exemple:
Ici, j'ai inclus le
-print0
et-0
(qui devrait être utilisé ensemble), afin de faire face à tout espace à l'intérieur des noms de fichiers et de répertoires.Voici une comparaison temporelle, entre les
xargs basename -a
xargs -n1 basename
versions et . (Par souci de comparaison, les synchronisations signalées ici sont après une exécution fictive initiale, afin qu'elles soient toutes les deux effectuées une fois que les métadonnées du fichier ont déjà été copiées dans le cache d'E / S.) J'ai canalisé la sortie verscksum
dans les deux cas, juste pour démontrer que la sortie est indépendante de la méthode utilisée.Comme vous pouvez le voir, il est vraiment beaucoup plus rapide d'éviter de lancer à
basename
chaque fois.la source
basename
acceptera plusieurs noms de fichiers sans avoir besoin d'arguments de ligne de commande supplémentaires. L'utilisation-a
ici est sous Linux. (basename --version
me ditbasename (GNU coreutils) 8.28
.)J'ai trouvé une solution (sur la page makandracards), qui donne juste le nom de fichier le plus récent:
(merci à Arne Hartherz)
Je l'ai utilisé pour
cp
:la source