Cara menambahkan file besar ke arsip dan menghapusnya secara paralel

8

Katakanlah saya memiliki file 80GB /root/bigfilepada sistem 100GB dan ingin meletakkan file ini dalam arsip /root/bigarchive.tar

Saya jelas perlu menghapus file ini pada saat yang sama ketika itu ditambahkan dalam arsip. Karena itu pertanyaan saya:

Bagaimana cara menghapus file pada saat yang sama ketika itu ditambahkan dalam arsip?

pengguna123456
sumber

Jawaban:

0

Jika Anda menggunakan tarperintah GNU , Anda dapat menggunakan --remove-filesopsi:

--Hapus file

hapus file setelah menambahkannya ke arsip

tar -cvf files.tar --remove-files my_directory
Dababi
sumber
5
Saya pikir OP ingin menghapus file pada saat yang sama itu diarsipkan, jadi jika --hapus-file menghapus setelah menambahkan file ke .tar, itu tidak akan membantu baginya karena hard disk-nya akan keluar dari ruang.
Zumo de Vidrio
6

Arsip tar terkompresi dari file tunggal terdiri dari header, file, dan pad trailing. Jadi masalah utama Anda adalah bagaimana menambahkan 512 byte header ke awal file Anda. Anda bisa mulai dengan membuat hasil yang diinginkan hanya dengan tajuk:

tar cf - bigfile | dd count=1 >bigarchive.tar

Kemudian salin 10G pertama file Anda. Untuk simpel, kami asumsikan dd Anda dapat membaca / menulis 1Gib sekaligus:

dd count=10 bs=1G if=bigfile >>bigarchive.tar

Kami sekarang membatalkan alokasi data yang disalin dari file asli:

fallocate --punch-hole -o 0 -l 10GiB bigfile

Ini menggantikan data dengan nol jarang yang tidak memakan ruang pada sistem file. Lanjutkan dengan cara ini, menambahkan a skip=10ke yang berikutnya dd, dan kemudian menambahkan fallocateoffset mulai ke -o 10GiB. Di bagian paling akhir tambahkan beberapa karakter nul untuk melengkapi file tar akhir.


Jika filesystem Anda tidak mendukung, fallocateAnda dapat melakukan hal serupa, tetapi mulai di akhir file. Pertama salin 10Gibytes terakhir dari file ke file perantara yang disebut, katakanlah part8,. Kemudian gunakan truncateperintah untuk mengurangi ukuran file asli. Lanjutkan dengan cara yang sama sampai Anda memiliki 8 file masing-masing 10Gibyte. Anda kemudian dapat menggabungkan tajuk dan part1untuk bigarchive.tar, lalu menghapus part1, dan kemudian menyatukan part2dan menghapusnya, dan seterusnya.

meuh
sumber
5

Menghapus file tidak selalu melakukan apa yang Anda pikirkan. Itu sebabnya dalam sistem mirip UNIX, pemanggilan sistem dipanggil unlinkdan tidak delete. Dari halaman manual:

unlink() deletes a name from the filesystem.  If that name was the last
link to a file and no processes have the file open, the file is deleted
and the space it was using is made available for reuse.

If the name was the last link to a file but any processes still have
the file open, the file will remain in existence until  the  last  file
descriptor referring to it is closed.

Akibatnya, selama kompresor data / pengarsipan membaca dari file, file itu tetap ada, menempati ruang dalam sistem file.

AlexP
sumber
1

Bagaimana cara menghapus file pada saat yang sama ketika itu ditambahkan dalam arsip?

Mengingat konteksnya, saya akan menafsirkan pertanyaan ini sebagai:

Cara menghapus data dari disk segera setelah dibaca, sebelum file lengkap telah dibaca, sehingga ada cukup ruang untuk file yang diubah.

Transformasi dapat berupa apa pun yang ingin Anda lakukan dengan data: mengompresi, mengenkripsi, dll.

Jawabannya adalah ini:

<$file gzip | dd bs=$buffer iflag=fullblock of=$file conv=notrunc

Singkatnya: baca data, lemparkan ke gzip (atau apa pun yang ingin Anda lakukan dengannya), buffer outputnya sehingga kami yakin akan membaca lebih banyak daripada yang kami tulis, dan menulisnya kembali ke file. Ini adalah versi yang lebih cantik dan menampilkan keluaran saat berjalan:

cat "$file" \
| pv -cN 'bytes read from file' \
| gzip \
| pv -cN 'bytes received from compressor' \
| dd bs=$buffer iflag=fullblock 2>/dev/null \
| pv -cN 'bytes written back to file' \
| dd of="$file" conv=notrunc 2>/dev/null

Saya akan melewatinya, baris demi baris:

cat "$file"membaca file yang ingin Anda kompres. Ini adalah penggunaan cat (UUOC) yang tidak berguna karena bagian selanjutnya, pv, juga dapat membaca file, tetapi saya menemukan ini lebih cantik.

Ini menyalurkannya ke pvyang menunjukkan informasi kemajuan ( -cNmemberi tahu 'gunakan semacam [c] ursor' dan beri nama [N]).

Itu pipa gzipyang jelas melakukan kompresi (membaca dari stdin, keluaran ke stdout).

Itu pipa ke yang lain pv(tampilan pipa).

Pipa itu menjadi dd bs=$buffer iflag=fullblock. The $buffervariabel adalah angka, sesuatu seperti 50 megabyte. Namun berapa banyak RAM yang ingin Anda dedikasikan untuk penanganan file Anda secara aman (sebagai titik data, buffer 50MB untuk file 2GB baik-baik saja). The iflag=fullblockmemberitahu dduntuk membaca hingga $bufferbyte sebelum pipa melalui. Pada awalnya, gzip akan menulis header, jadi output gzip akan mendarat di ddbaris ini . Kemudian ddakan menunggu hingga memiliki cukup data sebelum disalurkan, sehingga input dapat dibaca lebih lanjut. Selain itu, jika Anda memiliki bagian yang tidak dapat dikompresi, file output mungkin lebih besar dari file input. Buffer ini memastikan bahwa, hingga $bufferbyte, ini bukan masalah.

Kemudian kita pergi ke jalur tampilan pipa lain, dan akhirnya ke ddjalur output kami . Baris ini memiliki of(file output) dan conv=notruncditentukan, di mana notruncmemberitahu dduntuk tidak memotong (menghapus) file output sebelum menulis. Jadi, jika Anda memiliki 500 byte Adan Anda menulis 3 byte B, file tersebut akan BBBAAAAA...(bukannya diganti oleh BBB).

Saya tidak menutupi 2>/dev/nullbagian - bagiannya, dan itu tidak perlu. Mereka hanya merapikan output sedikit dengan menekan ddpesan "Saya sudah selesai dan menulis ini banyak byte". Garis miring terbalik pada akhir setiap baris ( \) membuat bash memperlakukan semuanya sebagai satu perintah besar yang saling menyambungkan satu sama lain.


Berikut ini skrip lengkap untuk memudahkan penggunaan. Secara anekdot, saya meletakkannya di folder bernama 'gz-in-place'. Saya kemudian menyadari akronim yang saya buat: GZIP: gnu zip in-place. Jadi dengan ini saya hadir, GZIP.sh:

#!/usr/bin/env bash

### Settings

# Buffer is how many bytes to buffer before writing back to the original file.
# It is meant to prevent the gzip header from overwriting data, and in case
# there are parts that are uncompressible where the compressor might exceed
# the original filesize. In these cases, the buffer will help prevent damage.
buffer=$((1024*1024*50)) # 50 MiB

# You will need something that can work in stream mode from stdin to stdout.
compressor="gzip"

# For gzip, you might want to pass -9 for better compression. The default is
# (typically?) 6.
compressorargs=""

### End of settings

# FYI I'm aware of the UUOC but it's prettier this way

if [ $# -ne 1 ] || [ "x$1" == "x-h" ] || [ "x$1" == "x--help" ]; then
    cat << EOF
Usage: $0 filename
Where 'filename' is the file to compress in-place.

NO GUARANTEES ARE GIVEN THAT THIS WILL WORK!
Only operate on data that you have backups of.
(But you always back up important data anyway, right?)

See the source for more settings, such as buffer size (more is safer) and
compression level.

The only non-standard dependency is pv, though you could take it out
with no adverse effects, other than having no info about progress.
EOF
    exit 1;
fi;

b=$(($buffer/1024/1024));
echo "Progressing '$1' with ${b}MiB buffer...";
echo "Note: I have no means of detecting this, but if you see the 'bytes read from";
echo "file' exceed 'bytes written back to file', your file is now garbage.";
echo "";

cat "$1" \
| pv -cN 'bytes read from file' \
| $compressor $compressorargs \
| pv -cN 'bytes received from compressor' \
| dd bs=$buffer iflag=fullblock 2>/dev/null \
| pv -cN 'bytes written back to file' \
| dd of="$1" conv=notrunc 2>/dev/null

echo "Done!";

Saya merasa ingin menambahkan garis buffering lain sebelum gzip, untuk mencegahnya menulis terlalu jauh ketika ddgaris buffering memancar, tetapi dengan hanya buffer 50MiB dan /dev/urandomdata 1900MB , sepertinya sudah berfungsi juga (md5sum cocok setelah dekompresi). Rasio yang cukup bagus untuk saya.

Peningkatan lainnya adalah deteksi tulisan yang terlalu jauh, tetapi saya tidak melihat cara melakukannya tanpa menghilangkan keindahan benda itu dan menciptakan banyak kerumitan. Pada titik itu, Anda mungkin juga membuatnya menjadi program python sepenuhnya yang melakukan semuanya dengan benar (dengan failafes untuk mencegah kerusakan data).

Luc
sumber