Domanda

Ho visto il seguente interessante utilizzo di tar negli script Bash di un collaboratore:

`tar cf - * | (cd <dest> ; tar xf - )`

Apparentemente funziona in modo molto simile a rsync -av, ma più veloce. La domanda sorge spontanea, come?

-m


MODIFICA : qualcuno può spiegare perché questa soluzione dovrebbe essere preferibile alla seguente?

cp -rfp * dest

Il primo è più veloce?

È stato utile?

Soluzione

Sulla differenza tra cp e tar per copiare le gerarchie di directory, è possibile condurre un semplice esperimento per mostrare la differenza:

alastair box:~/hack/cptest [1134]% mkdir src
alastair box:~/hack/cptest [1135]% cd src
alastair box:~/hack/cptest/src [1136]% touch foo
alastair box:~/hack/cptest/src [1137]% ln -s foo foo-s
alastair box:~/hack/cptest/src [1138]% ln foo foo-h
alastair box:~/hack/cptest/src [1139]% ls -a
total 0
-rw-r--r--  2 alastair alastair    0 Nov 25 14:59 foo
-rw-r--r--  2 alastair alastair    0 Nov 25 14:59 foo-h
lrwxrwxrwx  1 alastair alastair    3 Nov 25 14:59 foo-s -> foo
alastair box:~/hack/cptest/src [1142]% mkdir ../cpdest
alastair box:~/hack/cptest/src [1143]% cp -rfp * ../cpdest
alastair box:~/hack/cptest/src [1144]% mkdir ../tardest
alastair box:~/hack/cptest/src [1145]% tar cf - * | (cd ../tardest ; tar xf - )
alastair box:~/hack/cptest/src [1146]% cd ..
alastair box:~/hack/cptest [1147]% ls -l cpdest
total 0
-rw-r--r--  1 alastair alastair    0 Nov 25 14:59 foo
-rw-r--r--  1 alastair alastair    0 Nov 25 14:59 foo-h
lrwxrwxrwx  1 alastair alastair    3 Nov 25 15:00 foo-s -> foo
alastair box:~/hack/cptest [1148]% ls -l tardest
total 0
-rw-r--r--  2 alastair alastair    0 Nov 25 14:59 foo
-rw-r--r--  2 alastair alastair    0 Nov 25 14:59 foo-h
lrwxrwxrwx  1 alastair alastair    3 Nov 25 15:00 foo-s -> foo

La differenza sta nei file hard-linkati. Notare come i file hard-link vengono copiati singolarmente con cp e insieme a tar . Per rendere più evidente la differenza, dai un'occhiata agli inode per ciascuno:

alastair box:~/hack/cptest [1149]% ls -i cpdest
24690722 foo  24690723 foo-h  24690724 foo-s
alastair box:~/hack/cptest [1150]% ls -i tardest
24690801 foo  24690801 foo-h  24690802 foo-s

Probabilmente ci sono altri motivi per preferire tar, ma questo è uno grande, almeno se hai file ampiamente collegati.

Altri suggerimenti

Scrive l'archivio nell'output standard, quindi lo instrada in un sottoprocesso - racchiuso tra parentesi - che cambia in una directory diversa e legge / estrae dallo standard input. Questo è il significato del trattino dopo l'argomento f . Fondamentalmente sta copiando tutti i file visibili e le sottodirectory della directory corrente in un'altra directory.

Per una directory con 25.000 file vuoti:

$ time { tar -cf - * | (cd ../bar; tar -xf - ); }
real    0m4.209s
user    0m0.724s
sys 0m3.380s

$ time { cp * ../baz/; }
real    0m18.727s
user    0m0.644s
sys 0m7.127s

Per una directory con 4 file di 1073741824 byte (1 GB) ciascuno

$ time { tar -cf - * | (cd ../bar; tar -xf - ); }
real    3m44.007s
user    0m3.390s
sys 0m25.644s

$ time { cp * ../baz/; }
real    3m11.197s
user    0m0.023s
sys 0m9.576s

Suppongo che questo fenomeno sia fortemente dipendente dal filesystem. Se ho ragione vedrai una drastica differenza tra un filesystem specializzato in numerosi piccoli file, come reiserfs 3.6, e un filesystem che è più bravo a gestire file di grandi dimensioni.

(ho eseguito i test precedenti su HFS +.)

Questo è un uso unico di pipe. Fondamentalmente, il primo tar in genere scrive direttamente su un file, ma invece scriverà su stdout (il -), che viene quindi reindirizzato all'altro tar che prende stdin anziché un file. Fondamentalmente questa è la stessa cosa di cui è necessario eseguire il tarring su un file e non scriverlo più tardi, tranne senza il file in mezzo.

Il libro di PowerTools ha la copia come:

tar cf - * | (cd < dest > & amp; & amp; tar xvBf -)

Il '& amp; & amp;' è un condizionale che controlla il codice di ritorno del comando precedente. Cioè, se il "quot" cd " non riuscito, il " tar xf - " non sarebbe eseguito. Lancio sempre in -v (verbose) e in -B (input reblock).

Uso sempre tar. È particolarmente utile per la copia su un sistema remoto, come ad esempio:

tar cvf -. | ssh qualcuno @ somemachine '(cd somewhere & amp; & amp; tar xBf -)'

tar cf - * | (cd <dest> ; tar xf - )

eseguirà il tar di tutti i file / directory non nascosti della directory corrente su stdout, quindi eseguirà il piping in uno stdin di un nuovo sottoshell. Quella shell prima cambia la directory di lavoro corrente in < dest > , e poi la decomprime in quella directory.

Alcune vecchie versioni di cp non avevano opzioni -f / -p (e simili) per conservare i permessi, quindi questo trucco tar ha funzionato.

Credo che tar eseguirà un'operazione di "fusione" in stile Windows con directory profondamente annidate, mentre il cp sovrascriverà le sottodirectory.

Ad esempio se hai il layout:

dir/subdir/file1

e lo copi in una destinazione che contiene:

dir/subdir/file2

Quindi con la copia ti verrà lasciato con:

dir/subdir/file1
dir/subdir/file2

Ma con il comando tar, la tua destinazione conterrà:

<*>
tar cf - *

Usa tar per inviare * a stdout

|

Questo fa l'evidente reindirizzamento di stdout a ...

(cd <dest> ; tar xf - )

Questo, che cambia PWD nella posizione appropriata e quindi estrae da stdin

Non so perché questo sarebbe più veloce di rsync, in quanto non è implicata alcuna compressione.

La soluzione tar manterrà i collegamenti simbolici, mentre cp farà semplicemente copie e distruggerà i collegamenti.

tar è stata un'utilità Unix standard molto più a lungo di rsync. È più probabile trovarlo in una situazione in cui una gerarchia di directory deve essere copiata in un'altra posizione (anche un altro computer). rsync è probabilmente più facile da usare in questi giorni, ma è più lento perché confronta sia la sorgente che le destinazioni e le sincronizza. tar copia solo in una direzione.

Se hai GNU cp (che funzionerà con tutti i sistemi basati su Linux), cp --archive funzionerà, anche su file hard-link, e tar è non necessario.

Come succede, un collega ha scritto un comando quasi identico in uno dei nostri script. Dopo aver passato un po 'di tempo a scervellarmene, ho chiesto perché lo avesse usato piuttosto che cp . La sua risposta, come ricordo, è che cp è lento quando si effettua una copia da un file system a un altro.

Se questo sia vero richiederebbe più test di quanti io voglia spendere per la domanda, ma ha un certo senso. Il primo processo tar legge dal dispositivo sorgente il più rapidamente possibile solo aspettando che quel dispositivo legga. Nel frattempo, il secondo processo tar legge dalla sua pipe di input e scrive il più rapidamente possibile. Potrebbe essere necessario attendere l'input, ma se le scritture sul dispositivo di destinazione sono più lente di quelle sul dispositivo di origine, attenderà solo sul dispositivo di destinazione. Un singolo comando cp dovrà attendere sia sui dispositivi di origine che di destinazione.

D'altra parte, i moderni sistemi operativi svolgono un ottimo lavoro di pre-cache delle operazioni di I / O. È del tutto possibile che cp trascorrerà la maggior parte del tempo ad aspettare scritture e ad ottenere letture dalla memoria piuttosto che dal dispositivo stesso. Sembra che occorrerebbero dati veramente solidi per scegliere usando due comandi tar anziché il comando più semplice cp .

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