È possibile nidificare un 'find -exec' in un altro 'find -exec'?


14

Qualcosa di simile al seguente è quello che sto cercando, ma il mio codice non funziona, indipendentemente da come fuggo {}e+ ;

find ./ -maxdepth 1 -type d -name '.*' -exec \
    find {} -maxdepth 1 -type f -name '*.ini' -exec \
        md5sum \{\} \\; \;

Dopo aver visto questo Unix - & - domanda Linux , ho trovato che le seguenti opere di codice, ma non è nidificazione ritrovamento in quanto tale, e ho il sospetto che ci sia un modo migliore per fare questo lavoro particolare.

find ./ -maxdepth 1 -type d -name '.*' \
-exec bash -c 'for x; do
    find "$x" -maxdepth 1 -type f -name "*.ini" \
    -exec md5sum \{\} \;; \
done' _ {} \+

Esiste un modo per nidificare find -execsenza la necessità di invocare una shell (come sopra), con tutte le sue strane citazioni e vincoli di escape?

O può essere fatto direttamente in un singolo comando find, usando una combinazione dei suoi numerosi parametri?


4
Mentre può essere possibile fare ciò che stai chiedendo, quando le cose diventano così complesse, passo agli script shell o Perl. Il tuo secondo frammento di codice lo sta praticamente facendo, solo con lo script della shell in linea. Gli eroici one-liner sono divertenti, ma sono difficili da capire e quindi difficili da mantenere. A meno che non si tratti di un accordo one-shot in cui in qualche modo finisci per diventare bravo, non riesco a vedere una buona ragione per farlo oltre alla sfida intellettuale.
Warren Young,

1
@Warren Young: Certamente non penso che il concetto sia complesso, ma suppongo che tu intenda che non esiste un modo semplice per farlo find, ma se findnon puoi farlo, allora perché è findcosì riverito (?) Come lo strumento- da usare per trovare i file? ... Ho scoperto che find ./ -maxdepth 2 -path '.*/*.ini' -type f -exec md5sum {} \+funziona senza problemi nella mia situazione (il riferimento di jw013 -prunemi ha portato a questo nella pagina man), ma mi chiedo se sia un metodo robusto (in genere). Non l'ho mai usato find(in meno di un anno di Linux) come locateha fatto quasi tutto ciò di cui ho bisogno, quindi è un territorio sconosciuto.
Peter

1
Il -pathtest è esattamente quello che stavo per suggerire. Con questo, dovresti essere in grado di fare tutto ciò che vuoi (scusami per l'associazione Ace Of Base;))
rozcietrzewiacz

Risposte:


8

Vorrei provare a utilizzare una singola ricerca come:

find .*/ -maxdepth 1 -type f -name '*.ini' -execdir md5sum {} +

o anche (no findaffatto, solo gorgogliamento di shell)

md5sum .*/*.ini

anche se questo manca il -type fsegno di spunta, quindi funziona solo se non ci sono directory / non file che finiscono .ini. Se lo fai potresti usare

for x in .*/*.ini; do 
    if [ -f "$x" ]; then 
        md5sum "$x"
    fi
done

che perderebbe comunque il vantaggio di aver bisogno solo di una chiamata md5sum.

modificare

Per un metodo generale e sicuro di concatenamento find, puoi fare qualcosa di simile

find <paths> <args> -print0 | xargs -0 -I{.} find {.} <args for second find> [etc.]

Ottengo un errore con -f(f?), Quindi un altro errore con -execdir.. Quando sostituisco -execdir con -exec e / o sostituisco anche md5sum con print, non ottengo nulla ..
Peter.O

Grazie, per l'alternativa ... ma findsto cercando un modo per farlo usando ... Non è tanto che voglio solo risolvere questo esempio, sto cercando approfondimenti sui modi di find-fu .. forse c'è più lanugine che fu in find .. (non lo so, perché non l'ho mai praticamente usato), e questa è la prima situazione in cui ho voluto usarlo (per i file di immagini in realtà) e il -exec funzionalità di cui ho sentito parlare tanto sembra non essere così potente come la sua rep (?) allude a ... (+1 per le alternative, però) .. ma il tuo findesempio semplicemente non funziona (comunque )
Peter

Ottengo questo errore per il findcomando: ... find: The relative path ~ / bin 'è incluso nella variabile d'ambiente PATH, che è insicuro in combinazione con l'azione -execdir di find. Per favore rimuovi quella voce da $ PATH` ... Quindi forse funzionerà, ma devo dire che sto provando a sbarazzarmi di quel ~ / bin da un po 'di tempo ora ... Dovrò prendere più guardalo seriamente ... Non so dove l'ho impostato ... qualsiasi idea in cui potrebbe essere in agguato; il ~/binnel mio PERCORSO
Peter

Penso che il potere di findsia meglio apprezzato in situazioni che non possono essere fatte interamente con i globs, ma poiché questi tipi di situazioni sono rare, normalmente non ho bisogno di trovare molto.
jw013,

Va bene .. questo è un punto interessante e buono (sull'uso dei globs) ...
Peter.O

2

Il tuo problema originale non richiede di chiamare ricorsivamente, ma suppongo che non fosse questo il punto.

Credo che non sia possibile chiamare trovare ricorsivamente nel modo desiderato.

Quanto segue non è nemmeno chiamare find ricorsivamente (o nidificazione, come viene chiamato), ma non puoi semplicemente prendere un set di risultati del primo find e inviarlo al secondo? Ecco come farei istintivamente:

find `find ./ -maxdepth 1 -type d -name '.*'` \
    -maxdepth 1 -type f -name '*.ini' -exec md5sum {} \;

È inoltre possibile utilizzare xargsper eseguire la seconda ricerca.

Aggiornare:

Volevo aggiungere che poiché la maggior parte dei programmi di utilità UNIX accetta diversi argomenti relativi al nome del file anziché uno, di solito è possibile evitare del -exectutto:

md5sum `find \`find ./ -maxdepth 1 -type d -name '.*'\` -maxdepth 1 -type f -name '*.ini'`

Quando annidate i backtick aggiungete semplicemente le barre rovesciate \prima di quelle interne.

Se immaginiamo che md5sumprenda solo un argomento per il nome file, possiamo sempre inserirlo in un forciclo:

for f in `find \`find ./ -maxdepth 1 -type d -name '.*'\` -maxdepth 1 -type f -name '*.ini'`
do
    md5sum $f
done

Si noti che ciò diventa più difficile se -sono coinvolti nomi di file / directory che iniziano con o che contengono uno spazio. Le utility UNIX non giocano bene con loro. In questo caso l'aggiunta ./, --o che sono necessarie le virgolette.

Ovviamente l'esempio originale non è buono, perché potremmo semplicemente fare:

md5sum .*/*.ini

1
Hai dato una buona panoramica della situazione, ma tutti i findmetodi mostrati ottengono un errore quando un file / una directory contiene spazi ... md5sum .*/*.iniFunziona bene ... Sto iniziando a percepire in generale che * Warren Young's * il commento su cose che diventano "complesse" findavviene all'inizio del gioco :), ma suppongo che findsi realizzi quando i test delle condizioni sono più complicati, ma per quanto riguarda l'annidamento -exec, ho abbandonato l'idea, come sembra che ci siano modi più semplici per farlo .. (ma perl non è "semplice" per me (ancora) ...
Peter.O

0

Almeno sono riuscito a nidificare 2 comandi di ricerca:

find ~ -maxdepth 1 -type d -name '.*' -execdir \
    find {} -maxdepth 1 -type f -name '*.ini' \;

Ma non ho deciso di invocare un'altra chiamata -exec (dir) da lì.


Sì, questo è esattamente il mio problema :)
Peter

Sì, ma non annidare 3 non equivale a non annidare 2. :)
Utente sconosciuto l'
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.