Comprendre l'option -exec de find (1) (accolades et signe plus)

17

À l'aide de la commande suivante, quelqu'un pourrait-il expliquer quel est le but exact des accolades ({}) et du signe plus (+)?

Et comment le commandement fonctionnerait-il différemment s'ils étaient exclus du commandement?

find . -type d -exec chmod 775 {} +
Ryan Prentiss
la source

Réponses:

19

Les accolades seront remplacées par les résultats de la findcommande, et chmodseront exécutées sur chacun d'eux. Les +marques findtentent d'exécuter quelques commandes que possible (donc, chmod 775 file1 file2 file3par opposition à chmod 755 file1, chmod 755 file2, chmod 755 file3). Sans eux, la commande donne juste une erreur. Tout cela est expliqué dans man find:

-exec command ;

      Exécuter la commande ; true si l'état 0 est renvoyé. Tous les arguments suivants findsont considérés comme des arguments de la commande jusqu'à ce qu'un argument composé de « ;» soit 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. …

-exec command {} +

      Cette variante de l' -execaction 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. …

terdon
la source
12

En plus de la réponse de Terdon,

  • «Évidemment» -exec …doit se terminer par un point-virgule ( ;) ou un signe plus ( +). Est un Semicolon caractère spécial dans la coque (ou, au moins, tous les shell que j'ai jamais utilisé), donc, si elle doit être utilisée dans le cadre de la findcommande , il doit être échappé ou cité ( \;, ";"ou ';').
  • Avec -exec … ;, la {}chaîne peut apparaître un certain nombre de fois dans la commande, y compris zéro , ou deux ou plus, dans n'importe quelle position.  Voir ceci pour un exemple des raisons pour lesquelles vous pourriez vouloir vous -execpasser de l'utilisation {}.   Avoir deux ou plusieurs apparitions est utile principalement parce que, dans (au moins) certaines versions de find, le {}n'a pas besoin d'être un mot en soi; il peut avoir d'autres caractères au début ou à la fin; par exemple,

    find . -type f -exec mv {} {}.bak ";"
    

    Avec -exec … +, la {}chaîne doit apparaître comme dernier argument avant le +. Une commande comme

    find . -name "*.bak" -exec mv {} backup_folder +
    

    entraîne le find: missing argument to ‘-exec’message d'erreur énigmatique .

    • Une solution de contournement pour cela qui est spécifique aux commandes cpet mvest

      find . -name "*.bak" -exec mv -t backup_folder {} +
      

      ou

      find . -name "*.bak" -exec mv --target-directory=backup_folder {} +
      

    Le {}doit être un mot en soi; il ne peut pas avoir d'autres caractères au début ou à la fin. Et, dans (au moins) certaines versions de find, vous ne pouvez pas en avoir plus d'une {}.

  • Une note de raison: vous pouvez dire

    trouver . -name "* .sh" -type f -executable -exec {} arguments optionnels ici ";"

    pour exécuter chacun de vos scripts. Mais

    trouver . -nom "* .sh" -type f -exécutable -exec {} +

    exécute l' un de vos scripts, avec les noms de tous les autres comme paramètres. Cela revient à dire

    ./*.sh
    

    en tant que commande shell, sauf findqu'il ne garantit pas qu'il trie ses résultats, vous n'êtes donc pas assuré d'exécuter aaa.sh (votre premier *.shfichier par ordre alphabétique ) comme vous le feriez avec l'exécution ./*.sh.

  • Un aspect de findcela peut ne pas être parfaitement clair pour les débutants est que la ligne de commande est, en fait, une instruction exécutable dans un langage obscur. Par exemple,

    find . -name "*.sh" -type f -executable -print
    

    veux dire

    for each file
        if the file’s name matches `*.sh` (i.e., if it ends with `.sh`)
        then
            if it is a plain file (i.e., not a directory)
            then
                if it is executable (i.e., the appropriate `---x--x--x` bit is set)
                then
                    print the file’s name
                end if
            end if
        end if
    end loop
    

    ou simplement,

    for each file
        if the file’s name matches `*.sh`  AND  it is a plain file  AND  it is executable
        then
            print the file’s name
        end if
    end loop
    

    Certains -mots clés sont à la fois une action exécutable et un test. En particulier, cela est vrai pour -exec … ;; par exemple,

    find . -type f -exec grep -q cat {} ";" -print
    

    Se traduit par

    pour chaque fichier
        s'il s'agit d'un fichier ordinaire (c'est-à-dire pas d'un répertoire)
        ensuite
            exécuter grep -q cat nom de fichier
            si le processus réussit (c.-à-d. se termine avec le statut 0)
            ensuite
                imprimer le nom du fichier
            fin si
        fin si
    boucle de fin

    qui affichera les noms de tous les fichiers contenant la chaîne « cat». Et, alors que c'est quelque chose qui greppeut faire par lui-même (avec l' option -l(en minuscules L)), il peut être utile de l'utiliser avec findpour trouver des fichiers qui contiennent une certaine chaîne ET ont une certaine taille ET appartiennent à un certain propriétaire ET ont été modifiés dans un certain intervalle de temps,….

    Cependant, cela ne fonctionne pas pour -exec … +. Puisque -exec … +exécute une commande pour plusieurs fichiers, il n'est pas logique de l'utiliser comme condition logique dans une for each file …boucle.

  • L'inconvénient de ce qui précède est que findgénéralement se termine avec un état de sortie de 0, sauf si vous lui donnez des arguments non valides ou qu'il rencontre un répertoire qu'il ne peut pas lire. Même si un programme que vous exécutez échoue (quitte avec un état de sortie différent de zéro), findsortira avec un état de sortie de 0.  Sauf  si un programme que vous exécutez avec -exec … +échoue (quitte avec un état de sortie différent de zéro), findquittera avec un état de sortie non nul.

En plus d'un million de versions find(1) et de tests de ce qui findse fait réellement sur quelques systèmes, The Open Group Base Specifications Issue 7, 2013 Edition a fourni certaines informations sur ce qui finddoit, peut et ne doit pas faire.

G-Man dit «Réintègre Monica»
la source
3
Attention, votre exemple d'utilisation ... -exec mv {} {}.bak ...n'est pas garanti pour fonctionner comme prévu avec toutes les findimplémentations. Les états standard POSIX {}doivent apparaître seuls pour être toujours reconnus, sinon le comportement est libre de garder les caractères inchangés ou de les remplacer par le chemin. Dans le premier cas, votre commande entière supprimera essentiellement tous les fichiers sauf le dernier trouvé ...
jlliagre