Вместо извлечения архива tar


13

У меня есть небольшая дилемма здесь ...

Мне нужно было перенести файлы объемом около 70 ГБ с одного из моих серверов на другой, поэтому я решил, что их сборка и отправка архива будет самым быстрым способом.

Однако на принимающем сервере остается только 5 ГБ свободного места после получения архива tar.

Есть ли какой-нибудь способ, которым я могу извлечь tar «на месте»? Мне не нужно хранить архив после того, как он был извлечен, поэтому мне было интересно, возможно ли это сделать.

Изменить: Следует отметить, что архив уже был отправлен, и я хотел бы избежать повторной отправки другим способом.

Ответы:


11
% tar czf - stuff_to_backup | ssh backupmachine tar xvzf -

это переводится как:

  • tar и сожмите 'stuff_to_backup' в стандартный вывод
  • войти в систему с помощью ssh
  • запустите tar на 'backupmachine' и распакуйте все, что приходит из stdin

я лично использовал бы «rsync через ssh» для передачи материала, потому что вы можете продолжить передачу материала, если разрывается соединение:

% rsync -ar --progress -e 'ssh' 'stuff_to_backup' user@backupmachine:/backup/

который перенесет все из «stuff_to_backup» в папку «backup» на «backupmachine». если соединение разрывается, просто повторите команду. если некоторые файлы в "stuff_to_backup" изменятся, повторите материал, будет передана только разница.


Смотрите мой отредактированный вопрос
анонимный трус

@Charlie Somerville: да, вы упустили важную часть в первую очередь. :)
Акира

6

Если на другой машине есть ssh, я бы порекомендовал вам rsync в качестве другой альтернативы, которая не использует tar-файл:

rsync -avPz /some/dir/ user@machine:/some/other/dir/

И будьте осторожны с ведущими /

Изменить обновление

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

селективный экстракт:

$ tar xvf googlecl-0.9.7.tar googlecl-0.9.7/README.txt
googlecl-0.9.7/README.txt

выборочное удаление:

$ tar --delete --file=googlecl-0.9.7.tar googlecl-0.9.7/README.txt

Тем не менее, кажется, что вы потратите много времени на написание сценария для этого ...


Смотрите мой отредактированный вопрос
анонимный трус

Смотрите мой отредактированный ответ ... удачи: - /
YuppieNetworking

Спасибо за редактирование. Файлы на самом деле именуются числами, поэтому быстрый цикл for в bash может просто помочь.
анонимный трус

1
@Charlie Somerville: вам, возможно, придется начинать с файлов, хранящихся в конце tar, иначе вы можете закончить с tar, создающим новый архив ... так что сначала удалите файлы из конца tar.
Акира

5

По сути, вам нужна возможность направить файл в tar и «перебить» фронт по мере продвижения.

На StackOverflow кто-то спрашивал, как обрезать файл спереди , но кажется, что это невозможно. Вы все еще можете заполнить начало файла нулями особым образом, чтобы файл стал разреженным файлом , но я не знаю, как это сделать. Мы можем обрезать конец файла, хотя. Но tar должен читать архив вперед, а не назад.

Решение 1

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

Вам нужно написать программу (c, python, что угодно), чтобы обмениваться началом и концом файла, порциями и порциями, а затем передавать эти куски в tar при одновременном усечении файла порциями. Это основа для решения 2, которое, возможно, проще реализовать.

Решение 2

Другой способ - разделить файл на небольшие куски , а затем удалить их по мере их извлечения. Приведенный ниже код имеет размер фрагмента в один мегабайт, который можно настроить в зависимости от ваших потребностей. Чем больше, тем быстрее, но займет больше промежуточного пространства при разделении и во время извлечения.

Разделите файл archive.tar:

archive="archive.tar"
chunkprefix="chunk_"
# 1-Mb chunks :
chunksize=1048576

totalsize=$(wc -c "$archive" | cut -d ' ' -f 1)
currentchunk=$(((totalsize-1)/chunksize))
while [ $currentchunk -ge 0 ]; do
    # Print current chunk number, so we know it is still running.
    echo -n "$currentchunk "
    offset=$((currentchunk*chunksize))
    # Copy end of $archive to new file
    tail -c +$((offset+1)) "$archive" > "$chunkprefix$currentchunk"
    # Chop end of $archive
    truncate -s $offset "$archive"
    currentchunk=$((currentchunk-1))
done

Передайте эти файлы в tar (обратите внимание, нам нужна переменная chunkprefix во втором терминале):

mkfifo fifo
# In one terminal :
(while true; do cat fifo; done) | tar -xf -
# In another terminal :
chunkprefix="chunk_"
currentchunk=0
while [ -e "$chunkprefix$currentchunk" ]; do
    cat "$chunkprefix$currentchunk" && rm -f "$chunkprefix$currentchunk"
    currentchunk=$((currentchunk+1))
done > fifo
# When second terminal has finished :
# flush caches to disk :
sync
# wait 5 minutes so we're sure tar has consumed everything from the fifo.
sleep 300
rm fifo
# And kill (ctrl-C) the tar command in the other terminal.

Поскольку мы используем именованный канал ( mkfifo fifo), вам не нужно передавать все куски сразу. Это может быть полезно, если вы действительно ограничены в пространстве. Вы можете выполнить следующие шаги:

  • Переместите, скажем, последние 10Gb куски на другой диск,
  • Начните извлечение с кусками, которые у вас еще есть,
  • Когда while [ -e … ]; do cat "$chunk…; doneцикл завершен (второй терминал):
  • НЕ останавливайте tarкоманду, НЕ удаляйте fifo (первый терминал), но вы можете запустить sync, на всякий случай,
  • Переместите некоторые извлеченные файлы, которые, как вы знаете, завершены (tar не остановлен в ожидании данных для завершения извлечения этих файлов) на другой диск,
  • Переместить оставшиеся куски назад,
  • Возобновите извлечение, while [ -e … ]; do cat "$chunk…; doneснова запустив строки.

Конечно, это все как волатильность , вам нужно сначала проверить, все ли нормально в фиктивном архиве, потому что, если вы допустили ошибку, попрощайтесь с данными .

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

chunkprefix="chunk_"
currentchunk=0
while [ -e "$chunkprefix$currentchunk" ]; do
    cat "$chunkprefix$currentchunk" && rm -f "$chunkprefix$currentchunk"
    currentchunk=$((currentchunk+1))
done | tar -xf -

отказ

Обратите внимание, что для того, чтобы все это работало, ваша оболочка, хвост и усечение должны правильно обрабатывать 64-разрядные целые числа (для этого вам не нужен ни 64-разрядный компьютер, ни операционная система). Мой делает, но если вы запустите вышеупомянутый скрипт в системе без этих требований, вы потеряете все данные в archive.tar .

И в любом случае, если что-то не так, вы все равно потеряете все данные в archive.tar, поэтому убедитесь, что у вас есть резервная копия ваших данных.


0

Если у вас есть объектные файлы для перемещения, попробуйте удалить их. Это сэкономит значительное количество места.

$ strip `find . -name "*.bin"`
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.