Come integrare il comando mv dopo il comando find?


61

Sto cercando i file il cui nome contiene AAAnel loro percorso usando il seguente comando:

find path_A -name "*AAA*"

Dato l'output mostrato dal comando precedente, voglio spostare quei file in un altro percorso, diciamo path_B. Invece di spostare quei file uno per uno, posso ottimizzare il comando spostando quei file subito dopo il comando find?

Risposte:


87

Con GNU mv :

find path_A -name '*AAA*' -exec mv -t path_B {} +

Questo utilizzerà l' -execopzione find che sostituisce {}a turno ogni risultato find ed esegue il comando che gli dai. Come spiegato in man find:

   -exec command ;
          Execute  command;  true  if 0 status is returned.  All following
          arguments to find are taken to be arguments to the command until
          an  argument  consisting of `;' is encountered.  

In questo caso, stiamo utilizzando la +versione di in -execmodo da eseguire il minor numero mvpossibile di operazioni:

   -exec command {} +
          This  variant  of the -exec action runs the specified command on
          the selected files, but the command line is built  by  appending
          each  selected file name at the end; the total number of invoca‐
          tions of the command will  be  much  less  than  the  number  of
          matched  files.   The command line is built in much the same way
          that xargs builds its command lines.  Only one instance of  `{}'
          is  allowed  within the command.  The command is executed in the
          starting directory.

Non dimenticare il "\;" alla fine del dirigente!
Charles Roth,

@Charles Roth: è quello +che fa il lavoro, puoi leggere la mia citazione sopra o man findinvece
cuonglm

Grazie per questo! Stavo cercando di utilizzare -exec mv {} path_b +e non riuscivo con errori di autorizzazione. TBH, ancora non capisco perché, ma -exec mv -t path_b {} +funziona a meraviglia!
Jeremy Davis,

6
@JeremyDavis Quando si utilizza -exec ... {} +, {}deve essere l'ultima cosa prima di +. Questo è il motivo per cui usa mv -t destdir {} +e non mv {} destdir +. -exec mv {} destdir ';'Invece è stato utilizzato un solo cold , ma sarebbe stato eseguito mvuna volta per ogni file.
Kusalananda

23

Potresti fare anche qualcosa come sotto.

find path_A -name "*AAA*" -print0 | xargs -0 -I {} mv {} path_B

Dove,

  1. -0Se ci sono spazi vuoti o caratteri (comprese le nuove righe) molti comandi non funzioneranno. Questa opzione prende cura dei nomi dei file con uno spazio vuoto.
  2. -ISostituisci le occorrenze di replace-str negli argomenti iniziali con nomi letti dall'input standard. Inoltre, gli spazi vuoti non quotati non terminano gli elementi di input; invece il separatore è il carattere di nuova riga.

analisi

Ho creato due directory come sourcedire destdir. Ora, ho creato un mucchio di file dentro sourcedircome file1.bak, file2.bakefile3 with spaces.bak

Ora, ho eseguito il comando come,

find . -name "*.bak" -print0 | xargs -0 -I {} mv {} /destdir/

Ora, all'interno di destdir, quando lo faccio ls, ho potuto vedere che i file si sono spostati da sourcedira destdir.

Riferimenti

http://www.cyberciti.biz/faq/linux-unix-bsd-xargs-construct-argument-lists-utility/


22

A beneficio degli utenti di OS X che incontrano questa domanda, la sintassi in OS X è leggermente diversa. Supponendo di non voler cercare ricorsivamente in sottodirectory di path_A:

find path_A -maxdepth 1 -name "*AAA*" -exec mv {} path_B \;

Se vuoi cercare tutti i file in modo ricorsivo in path_A:

find path_A -name "*AAA*" -exec mv {} path_B \;

Questa non è una sintassi specifica per OS X, è la stessa con qualsiasi altra findche abbia mai usato. Aspetti -maxdepthpositivi : (soprattutto se path_B è una sottodirectory - evita di mvprovare a spostare i file già lì!) E usando \; (quindi {} non deve essere l'ultimo parametro e mvpuò essere utilizzata la sintassi normale )
drevicko il

6

Il -execmodo migliore per farlo. Se, per qualsiasi motivo, questa non è un'opzione, puoi anche leggere i risultati in un ciclo:

find path_A -name "*AAA*" -print0 | 
    while IFS= read -r -d $'\0' file; do mv "$file" path_B; done

Questo è il modo sicuro, può gestire nomi di file che contengono spazi, righe o altri caratteri strani. Un modo più semplice, ma che fallisce a meno che i nomi dei file non siano costituiti solo da semplici caratteri alfanumerici , è

mv $(find path_A -name "*AAA*") path_B

Ma usa il ciclo while.


Il modo più semplice può ancora fallire se your file names consist only of simple alphanumeric characters, ad esempio, se si raggiungeARG_MAX


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.