Интересное использование смолы... но что происходит?

Я видел следующее интересное использование tar в сопутствующем скрипте Bash:

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

По-видимому, он работает так же, как rsync -av, но быстрее. Возникает вопрос, как?

-m


EDIT. Может ли кто-нибудь объяснить, почему это решение предпочтительнее следующего?

cp -rfp * dest

Быстрее ли быстрее?

Ответ 1

По разнице между cp и tar для копирования иерархии каталогов можно провести простой эксперимент, чтобы показать разницу:

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

Разница заключается в файлах с жесткой привязкой. Обратите внимание, что файлы с жесткой привязкой копируются отдельно с помощью cp и вместе с tar. Чтобы сделать разницу более очевидной, посмотрите на индексные дескрипторы для каждого:

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

Вероятно, есть другие причины, по которым предпочитают tar, но это один большой, по крайней мере, если у вас есть файлы с жесткой привязкой.

Ответ 2

Он записывает архив в стандартный вывод, затем передает его в подпроцесс - завернутый скобками - который изменяется в другой каталог и считывает/извлекает из стандартного ввода. Это означает, что символ штриха после аргумента f означает. Он в основном копирует все видимые файлы и подкаталоги текущего каталога в другой каталог.

Ответ 3

Для каталога с 25 000 пустых файлов:

$ 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

Для каталога с 4 файлами размером 1073741824 байта (1 ГБ) каждый

$ 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

Я предполагаю, что это явление сильно зависит от файловой системы. Если я прав, вы увидите резкое различие между файловой системой, которая специализируется на многочисленных небольших файлах, таких как reiserfs 3.6, и файловой системе, которая лучше справляется с большими файлами.

(Я провел тесты выше на HFS +.)

Ответ 4

Это уникальное использование труб. В основном, первый tar обычно записывает непосредственно в файл, но вместо этого он записывает в stdout (-), который затем перенаправляется на другой tar, который принимает stdin, а не файл. В основном это то же самое, что и tarring для файла и разворачиваться позже, за исключением без файла между ними.

Ответ 5

В книге PowerTools есть копия как:

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

"& &" - это условие, которое проверяет код возврата предыдущей команды. Если бы "cd" потерпел неудачу, "tar xf -" не будет выполнен. Я всегда добавляю a -v (verbose) и a -B (вход в блок блокировки).

Я использую tar все время. Это особенно полезно для копирования в удаленную систему, например:

tar cvf -. | ssh кто-то @somemachine '(cd где-то & tar xBf -)'

Ответ 6

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

собирается деформировать все не скрытые файлы/каталоги текущего каталога на stdout, а затем переводит его в новый stdin подстроек. Эта оболочка сначала изменяет текущий рабочий каталог на <dest>, а затем переносит его в этот каталог.

Ответ 7

В некоторых старых версиях cp не было параметров -f/-p (и аналогичных) для сохранения разрешений, поэтому этот трюк tar выполнил задание.

Ответ 8

Я считаю, что tar будет выполнять операцию слияния в стиле Windows с глубоко вложенными каталогами, тогда как cp перезапишет подкаталоги.

Например, если у вас есть макет:

dir/subdir/file1

и вы скопируете его в пункт назначения, который содержит:

dir/subdir/file2

Затем с копией вы останетесь с:

dir/subdir/file1

Но с помощью команды tar ваша цель будет содержать:

dir/subdir/file1
dir/subdir/file2

Ответ 9

tar cf - *

Здесь используется tar для отправки * в stdout

|

Это делает очевидное перенаправление stdout на...

(cd <dest> ; tar xf - )

Это, что изменяет PWD в соответствующее место, а затем извлекает из stdin

Я не знаю, почему это будет быстрее, чем rsync, поскольку нет сжатия.

Ответ 10

Решение tar сохранит символические ссылки, тогда как cp просто сделает копии и уничтожит ссылки.

tar был стандартной утилитой Unix намного дольше, чем rsync. Скорее всего, вы найдете его в ситуации, когда иерархию каталогов нужно скопировать в другое место (даже на другом компьютере). rsync, вероятно, проще использовать в эти дни, но медленнее, потому что он сравнивает источник и адресаты и синхронизирует их. tar только копирует в одном направлении.

Ответ 11

Если у вас есть GNU cp (который все системы на базе Linux), cp --archive будет работать даже на файлы с жесткой связью, а tar не нужен.

Ответ 12

Как это происходит, сотрудник написал почти идентичную команду в один из наших скриптов. После того, как я немного озадачился, я спросил, почему он использовал это, а не cp. Его ответ, как я помню, заключался в том, что cp медленнее при копировании из одной файловой системы в другую.

Независимо от того, будет ли это истинно, потребуется больше тестирования, чем мне нужно потратить на этот вопрос, но это имеет определенный смысл. Первый tar процесс считывает из исходного устройства как можно быстрее, только ожидая, что это устройство будет считаться. Между тем второй tar процесс считывает из своего входного канала и записывает как можно быстрее. Возможно, придется ждать ввода, но если записи на целевом устройстве медленнее, чем на исходном устройстве, он будет ждать только на целевом устройстве. Одна команда cp должна будет ждать как источника, так и целевых устройств.

С другой стороны, современные операционные системы выполняют довольно хорошую работу по кэшированию операций ввода-вывода. Вполне возможно, что cp будет тратить большую часть своего времени на запись и считывание из памяти, а не самого устройства. Похоже, что нужны действительно надежные данные для выбора двух команд tar, а не более простой команды cp.