Mengapa tidak semua file dikompresi dan bagaimana meningkatkan solusinya

8

Saya memiliki folder dengan sekitar 20 ribu file. File-file tersebut dinamai sesuai dengan pola xy_{\d1,5}_{\d4}\.abc, misalnya xy_12345_1234.abc. Saya ingin mengompresi 10K pertama dari mereka menggunakan perintah ini:

ls | sort -n -k1.4,1.9 | head -n10000 | xargs tar -czf xy_0_10000.tar.gz

namun file yang dihasilkan hanya memiliki sekitar 2K file di dalamnya.

ls | sort -n -k1.4,1.9 | head -n10000 | wc -l namun mengembalikan 10.000, seperti yang diharapkan.

Sepertinya saya salah paham tentang sesuatu yang mendasar di sini ...

Saya menggunakan zsh 5.0.2 di Linux Mint 17.1, GNU tar 1.27.1

EDIT:

forking seperti yang disarankan oleh @Archemar terdengar sangat masuk akal, dengan garpu terbaru menimpa file yang dihasilkan - file tersebut berisi 'ekor' file - 7773 hingga 9999 .

hasil dari xargs --show-limit: Your environment variables take up 3973 bytes POSIX upper limit on argument length (this system): 2091131 POSIX smallest allowable upper limit on argument length (all systems): 4096 Maximum length of command we could actually use: 2087158 Size of command buffer we are actually using: 131072

mengganti -cdengan -ratau -utidak berfungsi dalam kasus saya. Pesan kesalahan tadinyatar: Cannot update compressed archives

menggunakan keduanya -rdan -utidak valid dan gagal dengantar: You may not specify more than one '-Acdtrux', '--delete' or '--test-label' option

mengganti -cdengan -atampaknya tidak valid juga dan gagal dengan yang sama tar: You must specify one of the '-Acdtrux', '--delete' or '--test-label' optionsmeskipun saya tidak mengenali masalah ini azfdan Acdtruxtampak terpisah bagi saya.

EDIT 2:

-T sepertinya cara yang baik, saya juga menemukan contoh di sini .

Namun ketika saya coba

ls | sort -n -k1.4,1.9 | head -n10000 | tar -czf xy_0_10000.tar.gz -T - saya mendapat tar: option requires an argument -- 'T'

baik, mungkin nama file tidak mencapai tar? Tapi sepertinya mereka, lakukan karena ketika aku mengeksekusinya

ls | sort -n -k1.4,1.9 | head -n10000 | tar --null -czf xy_0_10000.tar.gz -T - saya mendapat tar: xy_0_.ab\nxy_1_...<the rest of filenames separated by literal \n>...998.ab Cannot stat: File name too long

Jadi mengapa tar tidak melihat nama file?

kostja
sumber
dan jika Anda mencoba bukan c, dalam perintah tar?
Olivier Dulac
5
Relevan: Jangan parsing output darils
8bittree
1
File OP tidak memiliki nama yang rumit.
Archemar
@ 8bittree - juga saran umum untuk skrip shell yang kuat, ya. tetapi apa yang Anda sarankan untuk bekerja dengan daftar file dengan oneliners satu kali reguler?
kostja
1
@kostja saya gunakan find, yang memiliki -print0opsi untuk menggunakan byte nol sebagai pembatas, bukan baris baru. sortdapat mengatasinya dengan -zbendera. head, sayangnya tidak menangani mengerti pembatas byte nol, tetapi jawaban ini memiliki solusi menggunakan truntuk swap \ndan \0sebelum dan sesudah head. tarharus --null -T -membaca nama file yang dibatasi nol dari stdin.
8bittree

Jawaban:

12

Anda telah mencapai batas xargs?

xargs --show-limit

coba:

  • buat .tgzfile dummytar czf xy_0_10000.tar.gz /hello/world
  • ganti -czfdengan -Azf

ketika xarg mencapai batasnya, ia akan melakukan perintah fork, jadi perintah yang Anda jalankan tadi adalah

  tar czf xy_0_10000.tar.gz file1 file2 .... file666
  tar czf xy_0_10000.tar.gz file667 file668 ... file1203
  tar czf xy_0_10000.tar.gz file1024 ... file2000

karena setiap tar melewati yang sebelumnya, Anda hanya dapat tar cmenjalankan terakhir .

Edit:

1) menurut man tarpada unbuntu, -adan -r tampaknya menambahkan setara dilakukan oleh (baik) -A, --catenate, --concatenate

2) zip(tidak gzip) dapat digunakan untuk menambahkan file, mungkin opsi gzip akan melakukan trik. (gunakan | xargs zip -qr xy_0_0000.zip, ini akan menghasilkan file zip, bukan .tar.gz)

3) untuk menggunakan solusi @ rsanchez
Sangat penting untuk menambahkan opsi tar dengan cara yang tepat, cobalah

ls | sort -n -k1.4,1.9 | head -n10000 |tar -czf xy_0_10000.tar.gz -T -

where - -T -mean use option -Tdan gunakan -sebagai argumen untuk -T(Anda bisa menghasilkan daftar file /tmp/foo.lst, lalu gunakan -T /tmp/foo.lst)

Archemar
sumber
dapatkah (= tambah) alih-alih c (= buat / timpa) mengatasi batasan itu?
Olivier Dulac
@OlivierDulac ( Peringatan: Ini dugaan murni ) Mungkin tidak akan terpecahkan karena tar tidak dapat membuat file kosong. Anda dapat mengkompres folder kosong terlebih dahulu dan gunakan a (add)untuk menambahkan file ke file tar. Kemudian, Anda dapat membuka tar dan menghapus folder (menggunakan 7zip atau sesuatu)
Ismael Miguel
@ismaelmiguel: Saya cukup yakin ini akan dengan senang hati membuat file. jika tidak, cukup:touch xy_0_10000.tar.gz && { _the full command here_ ; }
Olivier Dulac
1
@OlivierDulac Itu akan menjadi .gzfile yang tidak valid .
Ismael Miguel
Semua halaman manual yang saya lihat dari manpages.ubuntu.com/manpages/vivid/en/man1/tar.1.html (15.04) kembali ke tepat (12.04) memiliki -rtambahan tetapi -akompres otomatis yang tidak setara. Dan -rztidak berfungsi: zipdapat menambah arsip yang ada karena direktori tidak dikompresi, tetapi tardengan kompresi kompres metatdata bersama dengan data. Anda dapat secara terpisah tar -rmenjadi arsip yang tidak dikompresi dan kemudian gzip hasilnya. Atau ...
dave_thompson_085
12

Tidak perlu xargs. Jika Anda langsung memberikan taryang -T -pilihan itu akan membaca nama file dari input standar.

Contohnya:

... | tar -T - -czf xy_0_10000.tar.gz
rsanchez
sumber
Saya kelihatannya menggunakan opsi ini dengan tidak benar, tidak bisa membuatnya bekerja dengan pipa. Telah mencoba ...| tar Tczf xy_..., ...| tar Tcz -f xy_... ...| tar -czf xy_... -T dan beberapa permutasi lainnya, tetapi saya hanya mendapatkan tar: You must specify one of the '-Acdtrux', '--delete' or '--test-label' options, tar: -f: Cannot stat: No such file or directoryjika menggunakan -fsecara terpisah dari opsi lain dan tar: option requires an argument -- 'T'. Bisakah Anda menambahkan contoh penggunaan?
kostja
Contoh @kostja ditambahkan.
rsanchez
Terima kasih banyak, rsanchez. Tidak yakin mengapa varian dengan -T -di akhir tardaftar opsi tidak berfungsi, tetapi contoh Anda berhasil. Sayangnya, pertanyaan saya sebenarnya memiliki dua bagian - sumber kesalahan dan kemungkinan perbaikan. Sementara Anda menyetujui yang terakhir, Archemar unggul di mantan dan hampir memiliki yang terakhir benar. Saya tidak yakin jawaban mana yang Anda terima karena keduanya jelas membantu.
kostja
1

Saya ingin melengkapi dua jawaban lain dengan solusi zsh , yang tidak mem-parsing ls , maupun membutuhkan xargs . Namun, saya tidak yakin sekarang, apakah itu juga menderita dari batasan panjang baris perintah.

  1. Tentukan fungsi yang menghasilkan kunci penyortiran yang Anda inginkan dengan memodifikasi $REPLY.

    sortkey() { REPLY=${REPLY[4,9]} }

    Ini setara dengan Anda sort -n -k1.4,1.9

  2. Buat array $filesdengan nama file yang diurutkan dengan fungsi di atas:

    files=(*(o+sortkey))

    Ini setara dengan ls | sort -n -k1.4,1.9

  3. Kembalikan 10.000 file pertama dengan

    ${files[0,9999]}

    Ini setara dengan ls | sort -n -k1.4,1.9 | head -n10000

Jadi, semua ini harus melakukan trik:

sortkey() { REPLY=${REPLY[4,9]} }
files=(*(o+sortkey))
tar -czf xy_0_10000.tar.gz ${files[0,9999]}
mpy
sumber