Is het mogelijk om 2 commandos te gebruiken in het -exec deel van find commando?

Ik heb zoiets geprobeerd als:

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

en ik krijg:

zoek: ontbrekend argument voor -exec
chmod: kan geen toegang krijgen {}: bestand of map bestaat niet
chmod: kan geen toegang krijgen;: bestand of map bestaat niet

Reacties

  • Merk op dat -name "*" overeenkomt met elke naam, dus het ' is een no-op-test die kan worden verwijderd. Bovendien zijn zowel chmod als chgrp heeft een -R optie voor recursieve bewerking.

Answer

Wat betreft het find commando, je kunt ook gewoon meer -exec commandos achter elkaar toevoegen:

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

Merk op dat dit commando het resultaat is t, equivalent van het gebruik van

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

op elk bestand.

Alle find “s parameters zoals -name, -exec, -size enzovoort, zijn eigenlijk tests : find zal ze een voor een blijven uitvoeren zolang de hele keten tot dusver is geëvalueerd als true . Dus elke opeenvolgende -exec -opdracht wordt alleen uitgevoerd als de vorige true (dwz 0 exit-status van de commandos). Maar find begrijpt ook logische operatoren zoals of (-o) en niet (!). Om daarom een ketting van -exec tests te gebruiken ongeacht van de vorige resultaten, je zou zoiets als dit moeten gebruiken:

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

Reacties

  • +1: Ja, dat ' is de meest elegante manier om het te doen. Als je kunt uitleggen waarom je '{}' (apostrofs rond de accolades) gebruikt, ga dan naar: unix.stackexchange.com/q/ 8647/4485
  • @user Helaas weet ik niet ' of het nog steeds nodig is. Ik heb zojuist een test gedaan en ben ' niet een situatie tegengekomen waarin het iets zou veranderen. Ik denk dat het ' slechts " goede praktijk " is die zal verdwijnen.
  • De aanhalingstekens zijn belangrijk voor bestanden met spaties in hun naam.
  • @ naught101 Nee, de aanhalingstekens kunnen nodig zijn in sommige niet-standaard shells, zoals fish en csh, maar zijn zeker niet nodig in POSIX-achtige shells (sh, dash, bash, zsh, ksh, yash).

Antwoord

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

Reacties

  • @Gilles: The wonders of -c ' s vreemde afhandeling van $ 0 doen me denken dat dit elke keer als ik ernaar kijk verkeerd is, maar het is absoluut correct.
  • Ik vind de expliciete shell die wordt gedefinieerd leuk …
  • Dit antwoord (en Giles ' is een swer) lijkt het betere antwoord op de vraag gezien de sh -c.

Antwoord

Uw commando wordt eerst door de shell geparseerd in twee commandos gescheiden door een ;, wat gelijk is aan een nieuwe regel:

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

Als je een shell-commando wilt uitvoeren, roep dan expliciet een shell aan met bash -c (of sh -c als het kan je niet schelen dat de shell specifiek bash is):

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

Let op het gebruik van {} als een argument tegen de schaal; het is het nulde argument (wat normaal de naam is van de shell of het script, maar dit maakt hier niet uit), daarom wordt er naar verwezen als "$0".

Je kunt meerdere bestandsnamen tegelijk aan de shell doorgeven en de shell er doorheen laten herhalen, het “zal sneller zijn. Hier geef ik _ door als de scriptnaam en de volgende argumenten zijn bestandsnamen, die for x (een snelkoppeling voor for x in "$@") herhalen.

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

Merk op dat sinds bash 4, of in zsh, je hier helemaal niets hoeft te vinden. Voer in bash (plaats het in uw ~/.bashrc) om **/ te activeren die staat voor een recursieve directory glob. (In zsh is dit de hele tijd actief.) Dan

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

of als je wilt dat de bestanden op volgorde worden herhaald

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

Een verschil met het find commando is dat de shell puntbestanden negeert (bestanden waarvan de naam begint met een . ). Om ze in bash op te nemen, stelt u eerst GLOBIGNORE=.:.. in; in zsh gebruikt u **/*(D) als het glob-patroon.

Reacties

  • Dit antwoord (en Glenn ' s antwoord) lijkt het betere antwoord op de vraag gezien de sh -c.
  • Zowel chgrp als chmod hebben een -R optie voor recursieve bewerking.

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *