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
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
etcsh
, 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
etchmod
ont un-R
option pour opération récursive.
-name "*"
correspond à tous les noms, donc ' un test sans opération qui peut être supprimé. De plus,chmod
etchgrp
a une option-R
pour les opérations récursives.