Domanda

Ho una directory di origine, ad esempio / my / source / directory / e una directory di destinazione, ad esempio / my / dest / directory / , che voglio rispecchiare con alcuni vincoli.

  • Voglio copiare i file che soddisfano determinati criteri del comando trova , ad esempio -ctime -2 (meno di 2 giorni) nella directory dest per rispecchiarlo
  • Voglio includere parte del prefisso, quindi so da dove proviene, ad es. / source / directory
  • Mi piacerebbe fare tutto questo con percorsi assoluti, quindi non dipende da quale directory corro
  • Immagino che non avere anche i comandi cd sia una buona pratica.
  • Voglio creare le sottodirectory se non esistono

Quindi

/my/source/directory/1/foo.txt -> /my/dest/directory/source/directory/1/foo.txt
/my/source/directory/2/3/bar.txt -> /my/dest/directory/source/directory/2/3/bar.txt

Ho hackerato insieme la seguente riga di comando ma sembra un po 'brutto, qualcuno può fare di meglio?

find /my/source/directory -ctime -2 -type f -printf "%P\n" | xargs -IFILE rsync -avR /my/./source/directory/FILE /my/dest/directory/

Per favore, commenta se pensi che dovrei aggiungere questa riga di comando come risposta, non volevo essere avido di reputazione.

È stato utile?

Soluzione

Ciò è notevolmente simile a una domanda (chiusa): Bash scripting copiare file senza sovrascrivere . La risposta che ho dato cita la soluzione 'find | cpio' menzionata in altre risposte (meno i criteri temporali, ma questa è la differenza tra 'simile' e 'stesso'), e delinea anche una soluzione usando GNU 'tar'.

ctime

Quando ho provato su Solaris, né GNU tar né (Solaris) cpio sono stati in grado di preservare l'impostazione ctime; anzi, non sono sicuro che ci sia un modo per farlo. Ad esempio, il comando touch può impostare l'atime o il mtime o entrambi - ma non il ctime. La chiamata di sistema utime() accetta anche solo i valori mtime o atime; non gestisce ctime. Quindi, credo che se trovi una soluzione che preserva il tempo di trasmissione, è probabile che quella soluzione sia specifica per la piattaforma. (Strano esempio: hackerare il dispositivo disco e modificare i dati nell'inode - non portatile, richiede privilegi elevati.) Rileggendo la domanda, però, vedo che "preservare ctime" non fa parte dei requisiti (phew); è semplicemente il criterio per stabilire se il file viene copiato o meno.

chdir

Penso che le operazioni 'cd' siano necessarie, ma possono essere completamente localizzate nello script o nella riga di comando, sebbene, come illustrato nella domanda citata e nelle righe di comando in basso, la seconda delle quali assume tar GNU .

(cd /my; find source/directory -ctime -2 | cpio -pvdm /my/dest/directory)

(cd /my; find source/directory -ctime -2 | tar -cf - -F - ) |
    (cd /my/dest/directory; tar -xf -)

Senza usare chdir() (aka find -print0), sono necessari strumenti o opzioni specializzati per gestire al volo la manipolazione dei nomi dei percorsi.

Nomi con spazi vuoti, nuove righe, ecc.

'xargs -0' e 'cpio' specifici per GNU sono molto potenti ed efficaci, come osservato da Adam Hawes. Stranamente, GNU --null ha un'opzione per gestire l'output da '-0', e cioè 'find' o la sua forma abbreviata '-u'. Quindi, usando GNU tar e GNU <=>, il comando sicuro è:

(cd /my; find source/directory -ctime -2 -print0 |
    cpio -pvdm0 /my/dest/directory)

Nota : questo non sovrascrive i file preesistenti nella directory di backup. Aggiungi <=> al comando <=> per questo.

Allo stesso modo, GNU <=> supporta <=> (apparentemente senza <=> forma abbreviata), e potrebbe anche essere usato:

(cd /my; find source/directory -ctime -2 -print0 | tar -cf - -F - --null ) |
    (cd /my/dest/directory; tar -xf -)

La gestione GNU dei nomi dei file con il terminatore null è estremamente intelligente e una preziosa innovazione (anche se ne sono venuto a conoscenza abbastanza di recente, per gentile concessione di SO; è stato in GNU tar per almeno un decennio).

Altri suggerimenti

Puoi provare cpio usando la modalità copia-passaggio, -p. Di solito lo uso con sovrascrivere tutto (-u), creare directory (-d) e mantenere il tempo di modifica (-m).

find myfiles | cpio -pmud target-dir

Tieni presente che find dovrebbe produrre nomi di percorso relativi, che non corrispondono ai tuoi criteri di percorso assoluti. Ovviamente questo freddo può essere 'risolto' usando cd, che non ti piace (perché no?)

(cd mypath; find myfiles | cpio ... )

Le parentesi genereranno una subshell e manterranno locale il cambio di stato (cioè il cambio di directory). Potresti anche definire una piccola procedura per sottrarre la "bruttezza".

SE stai usando trova sempre usa -print0 e reindirizza l'output attraverso xargs -0; bene quasi sempre. Il primo file con uno spazio nel suo nome eseguirà lo script se si utilizza l'output terminatore di nuova riga predefinito di find.

Sono d'accordo con tutti gli altri poster: usa cpio o tar se puoi. Farà quello che vuoi e salverà la seccatura.

Un'alternativa è usare tar, (cd $ SOURCE; tar cf -.) | (cd $ DESTINATION; tar xf -)

EDIT: Ah, mi sono perso un po 'di preservare CTIME. Credo che la maggior parte delle implementazioni di tar conserverà mtime, ma se preservare ctime è fondamentale, cpio è davvero l'unico modo.

Inoltre, alcune implementazioni tar (tar GNU uno) possono selezionare i file da includere in base a atime e mtime, anche se apparentemente non ctime.

#!/bin/sh

SRC=/my/source/directory
DST=/my/dest/directory

for i in $(find $SRC -ctime -2 -type f) ; do
    SUBDST=$DST$(dirname $i)
    mkdir -p $SUBDST
    cp -p $i $SUBDST
done

E suppongo, dal momento che vuoi includere " da dove proviene " ;, che userai diverse directory sorgente. Questo script può essere modificato per prendere la directory di origine come argomento semplicemente sostituendo la directory SRC = / my / source /, con SRC = $ 1

EDIT: istruzione if ridondante rimossa.

Non funziona quando i nomi dei file hanno spazi bianchi.

! / Usr / bin / sh

script per copiare file con la stessa struttura di directory "

echo " Inserisci il percorso completo della sorgente DIR (che inizia con / e termina con /): " leggi spath

echo " Inserire il percorso completo della posizione di destinazione (che inizia con / e termina con /): & Quot; leggi dpath

si = echo "$spath" | awk -F/ '{print NF-1}'

per fname in find $spath -type f -print fare CDIR = echo $fname | awk -F/ '{ for (i='$si'; i<NF; i++) printf "%s/", $i; printf "\n"; }' if [$ cdir]; poi         Se [ ! -d " $ dpath $ cdir " ]; poi                 mkdir -p $ dpath $ cdir         fi fi

cp $ fname $ dpath $ cdir

fatto

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top