web-dev-qa-db-fra.com

Utilisation du point-virgule (;) vs plus (+) avec exec dans find

Pourquoi y a-t-il une différence de sortie entre l'utilisation

find . -exec ls '{}' \+

et

find . -exec ls '{}' \;

J'ai eu:

$ find . -exec ls  \{\} \+
./file1  ./file2

.:
file1  file2  testdir1

./testdir1:
testdir2

./testdir1/testdir2:


$ find . -exec ls  \{\} \;
file1  file2  testdir1
testdir2
./file2
./file1
131
abc

Cela pourrait être mieux illustré par un exemple. Disons que find affiche ces fichiers:

file1
file2
file3

En utilisant -exec avec un point-virgule (find . -exec ls '{}' \;), s'exécutera

ls file1
ls file2
ls file3

Mais si vous utilisez plutôt un signe plus (find . -exec ls '{}' \+), autant de noms de fichiers que possible sont passés comme arguments à une seule commande:

ls file1 file2 file3

Le nombre de noms de fichiers n'est limité que par la longueur maximale de la ligne de commande du système. Si la commande dépasse cette longueur, la commande sera appelée plusieurs fois.

212
Martin

Jusqu'à présent, toutes les réponses sont correctes. Je propose cela comme une démonstration plus claire (pour moi) du comportement décrit en utilisant echo plutôt que ls:

Avec un point-virgule, la commande echo est appelée une fois par fichier (ou autre objet du système de fichiers) trouvé:

$ find . -name 'test*' -exec echo {} \;
./test.c
./test.cpp
./test.new
./test.php
./test.py
./test.sh

Avec un plus, la commande echo est appelée une seule fois. Chaque fichier trouvé est transmis en argument.

$ find . -name 'test*' -exec echo {} \+
./test.c ./test.cpp ./test.new ./test.php ./test.py ./test.sh

Si find génère un grand nombre de résultats, vous pouvez constater que la commande appelée s’étouffe sur le nombre d’arguments.

34
Johnsyweb

de l'homme

-exec commande;

Exécuter la commande; true si l'état 0 est renvoyé. Tous les arguments suivants à rechercher sont considérés comme des arguments de la commande jusqu'à ce qu'un argument composé de ';' est rencontré. La chaîne '{}' est remplacée par le nom de fichier actuel en cours de traitement partout où il apparaît dans les arguments de la commande, pas seulement dans les arguments où il est seul, comme dans certaines versions de find. Ces deux constructions peuvent avoir besoin d'être échappées (avec un '\') ou citées pour les protéger de l'expansion par le Shell. Voir la section EXEMPLES pour des exemples d'utilisation de l'option '-exec'. La commande spécifiée est exécutée une fois pour chaque fichier correspondant. La commande est exécutée dans le répertoire de départ. Il existe des problèmes de sécurité inévitables entourant l'utilisation de l'option -exec; vous devez plutôt utiliser l'option -execdir.

-exec commande {} +

Cette variante de l'option -exec exécute la commande spécifiée sur les fichiers sélectionnés, mais la ligne de commande est créée en ajoutant à la fin chaque nom de fichier sélectionné; le nombre total d'appels de la commande sera bien inférieur au nombre de fichiers correspondants. La ligne de commande est construite de la même manière que xargs construit ses lignes de commande. Une seule instance de '{}' est autorisée dans la commande. La commande est exécutée dans le répertoire de départ.

donc comme je le comprends, \; exécute des commandes séparées et + ajoute chaque nom. son essentiellement la façon dont il est exécuté, comme le\est une fuite donc son

ls testdir1; ls testdir2 

contre

ls testdir1 testdir2

faire ce qui précède dans mon Shell reflète la sortie de votre question.

MISE À JOUR 2

Alors, pourquoi voudriez-vous utiliser +

dis que j'ai deux fichiers 1.tmp et 2.tmp

1.tmp:

1
2
3

2.tmp:


2
3

fonctionnement

 find *.tmp -exec diff {} \;
> diff: missing operand after `1.tmp'
> diff: Try `diff --help' for more information.
> diff: missing operand after `2.tmp'
> diff: Try `diff --help' for more information.

où si vous utilisez + et concaténez les résultats de la recherche comme ceci:

find *.tmp -exec diff {} \+
1c1,3
< 1
---
> 0
> 2
> 30

dans ce cas, c'est la différence entre diff 1.tmp; diff 2.tmp et diff 1.tmp 2.tmp

Il y a des cas où \; est approprié et + sera nécessaire. l'utilisation de + avec rm en est un exemple, où si vous supprimez un grand nombre de fichiers, la vitesse est bien meilleure que. J'aime toujours en savoir plus sur la recherche, c'est un outil si puissant et pratique que j'espère que cela suffit pour expliquer les différences.

16
matchew

Voici l'affaire: find a une syntaxe spéciale. Vous utilisez le {} tels qu'ils sont car ils ont un sens à trouver car le chemin d'accès du fichier trouvé et (la plupart) des shells ne les interprètent pas autrement. Vous avez besoin de la barre oblique inversée \; parce que le point-virgule a une signification pour le Shell, qui le mange avant que find puisse l'obtenir. Donc ce que trouve veut voir APRÈS que le Shell soit fait, dans la liste des arguments passée au programme C, est

"-exec", "rm", "{}", ";"

mais vous avez besoin de \; sur la ligne de commande pour obtenir un point-virgule via le shell vers les arguments.

Vous pouvez vous en sortir avec \{\} parce que l'interprétation citée par Shell de \{\} est juste {}. De même, vous pouvez utiliser '{}'.

Ce que vous ne pouvez pas faire est d'utiliser

 -exec 'rm {} ;'

car le shell l'interprète comme un argument,

"-exec", "rm {};"

et "rm {};" n'est pas le nom d'une commande. (Du moins, à moins que quelqu'un ne tourne vraiment autour.)

Mise à jour

la différence est entre

$ ls file1
$ ls file2

et

$ ls file1 file2

Le + caténate les noms sur une ligne de commande.

9
Charlie Martin

La différence entre ; (point-virgule) ou + (signe plus) est la façon dont les arguments sont passés dans -exec/-execdir paramètre. Par exemple:

  • en utilisant ; exécutera plusieurs commandes (séparément pour chaque argument),

    Exemple:

    $ find /etc/rc* -exec echo Arg: {} ';'
    Arg: /etc/rc.common
    Arg: /etc/rc.common~previous
    Arg: /etc/rc.local
    Arg: /etc/rc.netboot
    

    Tous les arguments suivants de find sont considérés comme des arguments de la commande.

    La chaîne {} est remplacé par le nom du fichier en cours de traitement.

  • en utilisant + exécutera le moins de commandes possibles (car les arguments sont combinés ensemble). C'est très similaire au fonctionnement de la commande xargs, donc elle utilisera autant d'arguments par commande que possible pour éviter de dépasser la limite maximale d'arguments par ligne.

    Exemple:

    $ find /etc/rc* -exec echo Arg: {} '+'
    Arg: /etc/rc.common /etc/rc.common~previous /etc/rc.local /etc/rc.netboot
    

    La ligne de commande est créée en ajoutant à la fin chaque nom de fichier sélectionné.

    Une seule instance de {} est autorisé dans la commande.

Voir également:

1
kenorb