Est-il possible dutiliser 2 commandes dans la partie -exec de find commande?

Jai essayé quelque chose comme:

find . -name "*" -exec chgrp -v new_group {} ; chmod -v 770 {} \; 

et jobtiens:

find: argument manquant pour -exec
chmod: impossible daccéder {}: aucun fichier ou répertoire de ce type
chmod: impossible daccéder;: aucun fichier ou répertoire de ce type

Commentaires

  • Notez que -name "*" correspond à tous les noms, donc ' un test sans opération qui peut être supprimé. De plus, chmod et chgrp a une option -R pour les opérations récursives.

Réponse

Comme pour la commande find, vous pouvez également simplement ajouter dautres commandes -exec daffilée:

find . -name "*" -exec chgrp -v new_group "{}" \; -exec chmod -v 770 "{}" \; 

Notez que cette commande est, dans son résultat t, équivalent à utiliser

chgrp -v new_group file & & chmod -v 770 fichier

sur chaque fichier.

Tous les paramètres de find « tels que -name, -exec, -size et ainsi de suite, sont en fait des tests : find continuera à les exécuter un par un tant que la chaîne entière jusquà présent est évaluée à true . Ainsi, chaque commande -exec consécutive est exécutée uniquement si les précédentes ont renvoyé true (ie 0 état de sortie des commandes). Mais find comprend également les opérateurs logiques tels que ou (-o) et pas (!). Par conséquent, pour utiliser une chaîne de -exec tests indépendamment de des résultats précédents, il faudrait utiliser quelque chose comme ceci:

find . -name "*" \( -exec chgrp -v new_group {} \; -o -true \) -exec chmod -v 770 {} \; 

Commentaires

  • +1: Oui, cela ' est la manière la plus élégante de le faire. Si vous pouvez expliquer pourquoi vous utilisez '{}' (apostrophes autour des accolades), veuillez visiter: unix.stackexchange.com/q/ 8647/4485
  • @user Malheureusement, je ne ' pas savoir si cest encore nécessaire. Jai fait quelques tests tout à lheure et je nai ' pas rencontré une situation où cela changerait quoi que ce soit. Je suppose que ' est juste " bonne pratique " qui va séteindre.
  • Les guillemets sont importants pour les fichiers avec des espaces dans leurs noms.
  • @ naught101 Non, les guillemets peuvent être nécessaires dans certains shells non standard, tels que fish et csh, mais ne sont certainement pas nécessaires dans les shells de type POSIX (sh, dash, bash, zsh, ksh, yash).

Réponse

find . -name "*" -exec sh -c "chgrp -v new_group "$0" ; chmod -v 770 "$0"" {} \; 

Commentaires

  • @Gilles: Les merveilles de la manipulation étrange de -c ' de 0 $ me font penser que cest faux à chaque fois que jy jette un coup dœil, mais cest tout à fait correct.
  • Jaime que le shell explicite soit défini …
  • Cette réponse (et Giles ' est un swer) semble être la meilleure réponse à la question étant donné la sh -c.

Réponse

Votre commande est dabord analysée par le shell en deux commandes séparées par un ;, ce qui équivaut à une nouvelle ligne:

find . -name "*" -exec chgrp -v new_group {} chmod -v 770 {} \; 

Si vous souhaitez exécuter une commande shell, appelez explicitement un shell avec bash -c (ou sh -c si vous ne vous souciez pas que le shell soit spécifiquement bash):

find . -name "*" -exec sh -c "chgrp -v new_group "$0"; chmod -v 770 "$0"" {} \; 

Notez lutilisation de {} comme argument au shell; cest largument zéro (qui est normalement le nom du shell ou du script, mais cela na pas dimportance ici), donc référencé comme "$0".

Vous pouvez passer plusieurs noms de fichiers au shell à la fois et faire passer le shell à travers eux, ce sera plus rapide. Ici, je passe _ comme nom de script et les arguments suivants sont noms de fichiers sur lesquels for x (un raccourci pour for x in "$@") itère.

find . -name "*" -exec sh -c "for x; do chgrp -v new_group "$x"; chmod -v 770 "$x"; done" _ {} + 

Notez que depuis bash 4, ou dans zsh, vous navez pas besoin de trouver du tout ici. Dans bash, exécutez shopt -s globstar (mettez-le dans votre ~/.bashrc) pour activer **/ représentant un répertoire récursif glob. (En zsh, cest actif tout le temps.) Puis

chgrp -v new_group -- **/*; chmod -v 770 -- **/* 

ou si vous voulez que les fichiers soient itérés dans lordre

for x in **/*; do chgrp -v new_group -- "$x" chmod -v 770 -- "$x" done 

Une différence avec la commande find est que le shell ignore les fichiers de points (fichiers dont le nom commence par . ). Pour les inclure, dans bash, commencez par définir GLOBIGNORE=.:..; dans zsh, utilisez **/*(D) comme modèle global.

Commentaires

  • Cette réponse (et la réponse de Glenn ') semble être la meilleure réponse à la question étant donné le sh -c.
  • Les deux chgrp et chmod ont un -R option pour opération récursive.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *