trova -exec nello script bash con espansione variabile


14

Sto cercando di eseguire un comando simile a quello seguente in uno script bash. Dovrebbe cercare in tutte le sottocartelle di $sourcedire copiare tutti i file di un certo tipo al livello principale di $targetdir.

#!/bin/bash

# These are set as arguments to the script, not hard-coded
sourcedir="/path/to/sourcedir"
targetdir="/path/to/targetdir"

find "$sourcedir" -type f -name "*.type" -exec sh -c 'cp "$1" "$2/`basename "$1"`"' "{}" "$targetdir" \;

Questo sembra essere abbastanza vicino, solo che {}non viene passato come $2a-exec sh -c ...

Vorrei farlo il più vicino possibile al "modo giusto", con tolleranza per i caratteri speciali nei nomi dei file (in particolare i caratteri a virgoletta singola).

Modifica: vedo persone che suggeriscono l'utilizzo xargso l'argomentazione di argomenti. Avevo l'impressione che questo andasse bene solo per un numero limitato di argomenti. Se ad esempio ho migliaia di file .jpg che sto provando a copiare da una serie di directory della galleria in una gigantesca directory di presentazione, le soluzioni che concatenano gli argomenti continueranno a funzionare?

Modifica 2: il mio problema era che mancava una _prima della mia prima opzione per inserire il -execcomando. Per chiunque sia curioso di sapere come far funzionare il comando find, aggiungi il _e tutto andrà bene:

find "$sourcedir" -type f -name "*.type" -exec sh -c 'cp "$1" "$2"' _ "{}" "$targetdir" \;

Ho accettato una risposta qui sotto però perché svolge lo stesso compito, ma è più efficiente ed elegante.


4
Questo è esattamente il motivo per cui è xargsstato mai creato, per gestire automaticamente enormi quantità di argomenti su comandi regolari con limiti. Inoltre, la maggior parte dei limiti massimi degli argomenti è stata notevolmente migliorata per i programmi di utilità GNU standard. Vedrai anche un vantaggio in termini di prestazioni, evitando tutte quelle forcelle di processo, che su migliaia di file è rilevante.
JM Becker,

Con gnu-find e + invece di ";", puoi anche gestire più argomenti contemporaneamente con find. E salvi l'argomento complicato passando con -print0.
utente sconosciuto

@userunknown: rispondo a questo sotto la tua risposta.
JM Becker,

@utente sconosciuto Bene, ADORO questo codice. È almeno completamente conforme a POSIX e funzionerà senza alcun elemento GNU sulla macchina. Ci sono quei momenti in cui si fa bisogno di questo, soprattutto su server sul lavoro.
syntaxerror,

Risposte:


6

Vuoi copiare file di un tipo specifico, in una directory specifica? È meglio farlo xargse non ne hai nemmeno bisogno sh. Questo è un modo più appropriato per farlo, dovrebbe anche funzionare in modo più efficiente.

find "$sourcedir" -type f -name "*.type" | xargs cp -t targetdir

Se è necessario gestire nomi di file speciali, utilizzare NULLcome separatore

find "$sourcedir" -type f -name "*.type" -print0 | xargs -0 cp -t "$targetdir"

1
Per il secondo caso, non dimenticare di aggiungere -print0a finded -0axargs
SiegeX

@ SiegeX, lo stavo già facendo, prima di notare il tuo commento.
JM Becker,

Inoltre, NULLnon è necessario se lo usi '{}', è importante quando non lo fai. Il vero vantaggio tra gli altri, oltre alla POSIXconformità, è la prestazione.
JM Becker,

6

È necessario passare {}come argomento alla shell, quindi scorrere su ogni argomento.

find "$sourcedir" -type f -name "*.type" -exec sh -c 'for f; do cp "$f" "$0"; done' "$targetdir" {} +

Nota : il modo in cui funziona è che il primo argomento di una shell è il nome della shell , possiamo sfruttarlo passando il nome come $targetdire quindi utilizzare il parametro speciale $0all'interno dello script della shell per accedere a targetdir.


1
"$targetdir"non viene espanso tra virgolette singole.
enzotib,

5

Se non credi nella chiesa di Xargs:

find "$sourcedir" -type f -name "*.mp3" -exec cp -t "$targetdir" {} +

Spiegazione:

cp -t a b c d 

copia b, c e d nella directory di destinazione a.

-exec cmd {} +

invoca il comando su una grande quantità di file contemporaneamente, non uno dopo l'altro (che è standard, se si utilizza ";"invece di +). Questo è il motivo per cui devi tirare il targetdir in primo piano e contrassegnarlo esplicitamente come target.

Funziona con gnu-find e potrebbe non funzionare con altre implementazioni di find. Ovviamente si basa anche sulla -t-flag.

TechZilla è ovviamente all'estrema destra, in quanto shnon è necessario per invocare cp.

Se non lo usi xargs, il che è il più delle volte inutile in combinazione con find, sei salvato dall'apprendimento del -print0e -0flag.


1
Ovviamente, quale metodo qualcuno potrebbe preferire è alquanto soggettivo. Detto questo, esistono motivi per continuare a usarli xargs. Il più grande esempio, cosa succede se non si trovano file? Uso sempre xargs al posto di forloop generali , findè di portata molto più piccola. Inoltre, findsupporta solo che +se si utilizza GNU find, non è definito in POSIX. Quindi, anche se dovresti sentirti libero di preferire findda solo, non fa tutto ciò che fa xargs. Quando consideri GNU xargsottieni anche -Pciò che fa multi-core. Vale la pena imparare a xargsprescindere.
JM Becker,

Parlando di soggettività, la mia opinione ovviamente differisce. Oggettivamente, anche la tua risposta è corretta. È una delle poche migliori soluzioni disponibili.
JM Becker,

@TechZilla: spero di ricordare di visitare nuovamente questo sito, quando find inizia a supportare l'invocazione parallela. :) Nella maggior parte dei casi con la copia / spostamento, la velocità del disco sarà il fattore limitante, ma gli SSD potrebbero cambiare l'immagine. Hai ragione, che una soluzione non GNU da fornire è un'ottima cosa. Altrimenti, la soluzione find è oggettivamente più breve, più semplice e utilizza solo due processi.
utente sconosciuto

0
read -p "SOURCE: " sourcedir
read -p "TYPE: " type
read -p "TARGET: " targetdir
find -L $sourcedir -iname "*.$type" -exec cp -v {} $targetdir \;

3
Valuta di aggiungere qualche spiegazione della tua soluzione.
HalosGhost
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.