Comment utiliser la commande find pour lister les noms de fichiers mais pas le chemin?

Jan 06 2021

J'ai vérifié certaines réponses en ligne, mais elles ne fonctionnent pas quand il y a un -nameparamètre dans la commande (peut-être que je fais quelque chose de mal, pas sûr). Ce que j'aimerais faire est de ne lister que les noms de fichiers (pas le répertoire / chemin), et pour compliquer davantage, j'ai le même nom de fichier avec une extension différente, donc je dois filtrer le résultat en utilisant -nameet -o, le problème est les suggestions que je vu utiliser soit -printfou basename, et cela ne fonctionne pas bien quand il y en a -name *.txt -o name *.pdf. Existe-t-il un autre moyen de résoudre ce problème?

Exemple de mes fichiers:

/dir1/dir2/dir3/dir4/
                    /file1.txt
                    /file1.pdf
                    /file1.ods ...etc.

Je ne suis intéressé que par la liste d'un ou plusieurs types de fichiers par liste (en utilisant -namepour filtrer mes résultats.

Est-il possible de l'accomplir en utilisant seulement 1 findcommande ou je dois le faire en 2 étapes (enregistrer le résultat dans un fichier temporaire, puis filtrer / supprimer le répertoire du fichier temporaire)? Le résultat que j'essaie d'accomplir est un fichier texte avec un nom de fichier par ligne:

file1.txt
file1.pdf
file1.ods
file2.txt
file2.pdf
etc.

La commande que j'utilisais est

find /dir1/dir2/dir3/dir4/ -type f -name '*.txt' -o -name '*.pdf' -o -name '*.ods' -printf "%f\n"

J'utilise GNU find.

Mise à jour

Il s'est avéré que je dois mettre \(...\), comme l'a rappelé αғsнιη

Réponses

3 αғsнιη Jan 06 2021 at 21:02

Lorsque vous utilisez plusieurs expressions en mode OU logique avec, -ovous devez toutes les insérer \( ... \), sinon le dernier résultat de l'expression est toujours respecté; et -printf '%f\n'est utilisé pour imprimer le nom des fichiers uniquement avec tous les principaux répertoires supprimés.

find . -type f \( -name '*.pdf' -o -name '*.txt' \) -printf '%f\n'

voir man findsous la section OPÉRATEURS sur ( expr ):

OPÉRATEURS
...

(expr)
Force la priorité. Puisque les parenthèses sont spéciales pour le shell, vous devrez normalement les citer.

vous pouvez donc utiliser \( ... \)ou '(' ... ')'(les espaces après et avant les parenthèses sont importants) pour les échapper.

1 Kusalananda Jan 06 2021 at 22:58

Comme cela a déjà été mentionné, vous devez regrouper vos -nametests entre parenthèses. Ces parenthèses doivent être échappées comme \( ... \)ou entre guillemets, par exemple '(' ... ')'pour les protéger du shell (où elles désigneraient autrement un sous-shell).

En utilisant standard findet en facilitant légèrement la gestion des suffixes de nom de fichier:

set -- txt pdf ods

for suffix do
    set -- "$@" -o -name "*.$suffix"
    shift
done
shift

find /dir1/dir2/dir3/dir4 \( "$@" \) -type f -exec basename {} \;

Cela définit d'abord les paramètres de position sur la liste des suffixes de nom de fichier que nous aimerions voir (cela pourrait également être pris à partir de la ligne de commande s'il s'agit d'un script), et construit la liste OR des -nametests. Ceci est ensuite utilisé dans la findligne de commande.

La findcommande elle-même appelle ensuite l' basenameutilitaire pour chaque nom trouvé.

Comme alternative, nous pourrions utiliser à la place une substitution de paramètre pour supprimer tout sauf le composant de nom de fichier de chaque chemin, mais pour ce faire, nous devons passer les noms de chemin à un sh -cscript en ligne :

# [...] as before [...]

find /dir1/dir2/dir3/dir4 \( "$@" \) -type f -exec sh -c '
    for pathname do
        printf "%s\n" "${pathname##*/}"
    done' sh {} +

Je m'attendrais à ce que cela s'exécute plus rapidement que la variante utilisant basename, du moins s'il y a beaucoup de noms de fichiers à gérer, bien qu'avec GNU basenamede coreutils, vous pouvez utiliser -aou --multipleaimer ainsi:

find /dir1/dir2/dir3/dir4 \( "$@" \) -type f -exec basename -a {} +

Cela appellerait basenamele moins de fois possible. Mais là encore, si vous aviez installé coreutils, vous pourriez aussi avoir findutils, avec GNU find, et vous pourriez utiliser -printf '%f\n'pour faire la même chose.