Réponses:
Dans GNU, findvous pouvez utiliser des -printfparamètres pour cela, par exemple:
find /dir1 -type f -printf "%f\n"
-oa une priorité inférieure à celle implicite -a, vous voudrez donc souvent regrouper vos -oarguments)
Si votre recherche n'a pas d'option -printf, vous pouvez également utiliser le nom de base:
find ./dir1 -type f -exec basename {} \;
... {} ';'
Utilisation -execdirqui contient automatiquement le fichier actuel {}, par exemple:
find . -type f -execdir echo '{}' ';'
Vous pouvez également utiliser $PWDau 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:
find . -type f -execdir basename '{}' ';'
-execdir utility [argument ...] ;Le
-execdirprincipal est identique au-execprincipal, à l'exception que l'utilitaire sera exécuté à partir du répertoire qui contient le fichier actuel .
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.
./filenameau lieu de filename. Selon vos besoins, cela peut ou peut ne pas être bien.
$PWDau lieu de ..
Si vous utilisez GNU find
find . -type f -printf "%f\n"
Ou vous pouvez utiliser un langage de programmation tel que Ruby (1.9+)
$ ruby -e 'Dir["**/*"].each{|x| puts File.basename(x)}'
Si vous avez envie d'une solution bash (au moins 4)
shopt -s globstar
for file in **; do echo ${file##*/}; done
Si vous souhaitez exécuter une action uniquement contre le nom de fichier, utilisez basename peut être difficile.
Par exemple ceci:
find ~/clang+llvm-3.3/bin/ -type f -exec echo basename {} \;
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 xargsla sortie. par exemple pour tuer les fichiers dans un répertoire basé sur des noms dans un autre répertoire:
cd dirIwantToRMin;
find ~/clang+llvm-3.3/bin/ -type f -exec basename {} \; | xargs rm
find ~/clang+llvm-3.3/bin/ -type f -exec basename {} \;
-execet -execdirsont lents, xargsest roi.
$ alias f='time find /Applications -name "*.app" -type d -maxdepth 5'; \
f -exec basename {} \; | wc -l; \
f -execdir echo {} \; | wc -l; \
f -print0 | xargs -0 -n1 basename | wc -l; \
f -print0 | xargs -0 -n1 -P 8 basename | wc -l; \
f -print0 | xargs -0 basename | wc -l
139
0m01.17s real 0m00.20s user 0m00.93s system
139
0m01.16s real 0m00.20s user 0m00.92s system
139
0m01.05s real 0m00.17s user 0m00.85s system
139
0m00.93s real 0m00.17s user 0m00.85s system
139
0m00.88s real 0m00.12s user 0m00.75s system
xargsLe parallélisme aide également.
Curieusement, je ne peux pas expliquer le dernier cas de xargssans-n1 . Il donne le résultat correct et c'est le plus rapide¯\_(ツ)_/¯
( basenameprend seulement 1 argument de chemin mais xargsles 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 -execdiraide, mais toujours beaucoup plus lentement qu'un parallèle xargs:
$ alias f='time find /usr/ -maxdepth 5 -type d'
$ f -exec basename {} \; | wc -l; \
f -execdir echo {} \; | wc -l; \
f -print0 | xargs -0 -n1 basename | wc -l; \
f -print0 | xargs -0 -n1 -P 8 basename | wc -l
2358
3.63s real 0.10s user 0.41s system
2358
1.53s real 0.05s user 0.31s system
2358
1.30s real 0.03s user 0.21s system
2358
0.41s real 0.03s user 0.25s system
findc'est -execdircelui qui devient le plus rapide car la création de nouveaux processus est une opération relativement coûteuse.
Honnêtement basename, les dirnamesolutions sont plus faciles, mais vous pouvez également vérifier ceci:
find . -type f | grep -oP "[^/]*$"
ou
find . -type f | rev | cut -d '/' -f1 | rev
ou
find . -type f | sed "s/.*\///"
Comme d'autres l'ont souligné, vous pouvez combiner findet basename, mais par défaut, le basenameprogramme ne fonctionnera que sur un chemin à la fois, donc l'exécutable devra être lancé une fois pour chaque chemin (en utilisant l'un find ... -execou l' autre find ... | xargs -n 1), ce qui peut potentiellement être lent.
Si vous utilisez l' -aoption on basename, elle peut accepter plusieurs noms de fichiers en une seule invocation, ce qui signifie que vous pouvez ensuite utiliser xargssans le -n 1, pour regrouper les chemins d'accès en un nombre beaucoup plus faible d'invocations de basename, ce qui devrait être plus efficace.
Exemple:
find /dir1 -type f -print0 | xargs -0 basename -a
Ici, j'ai inclus le -print0et-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 -axargs -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 vers cksumdans les deux cas, juste pour démontrer que la sortie est indépendante de la méthode utilisée.
$ time sh -c 'find /usr/lib -type f -print0 | xargs -0 basename -a | cksum'
2532163462 546663
real 0m0.063s
user 0m0.058s
sys 0m0.040s
$ time sh -c 'find /usr/lib -type f -print0 | xargs -0 -n 1 basename | cksum'
2532163462 546663
real 0m14.504s
user 0m12.474s
sys 0m3.109s
Comme vous pouvez le voir, il est vraiment beaucoup plus rapide d'éviter de lancer à basenamechaque fois.
basenameacceptera plusieurs noms de fichiers sans avoir besoin d'arguments de ligne de commande supplémentaires. L'utilisation -aici est sous Linux. ( basename --versionme dit basename (GNU coreutils) 8.28.)