Loại bỏ hiệu quả (các) tệp khỏi .tgz lớn


14

Giả sử tôi có một tệp nén nén gzip tarArchive.tgz (+100 tệp, tổng cộng + 5gb).

Điều gì sẽ là cách nhanh nhất để loại bỏ tất cả các mục khớp với một mẫu tên tệp đã cho ví dụ tiền tố * .jpg và sau đó lưu trữ phần còn lại trong một gzip: ed tar-ball một lần nữa?

Thay thế kho lưu trữ cũ hoặc tạo một kho lưu trữ mới không quan trọng, cái nào nhanh nhất.


Câu trả lời:


14

Với GNU tar, bạn có thể làm:

pigz -d < file.tgz |
  tar --delete --wildcards -f - '*/prefix*.jpg' |
  pigz > newfile.tgz

Với bsdtar:

pigz -d < file.tgz |
  bsdtar -cf - --exclude='*/prefix*.jpg' @- |
  pigz > newfile.tgz

( pigzlà phiên bản đa luồng của gzip).

Bạn có thể ghi đè lên tệp như:

{ pigz -d < file.tgz |
    tar --delete --wildcards -f - '*/prefix*.jpg' |
    pigz &&
    perl -e 'truncate STDOUT, tell STDOUT'
} 1<> file.tgz

Nhưng điều đó khá rủi ro, đặc biệt là nếu kết quả cuối cùng bị nén ít hơn tệp gốc (trong trường hợp đó, phần thứ hai pigzcó thể kết thúc các vùng ghi đè của tệp mà tệp đầu tiên chưa đọc).


cảm ơn câu trả lời, nâng cao. sẽ chạy điểm chuẩn vào tuần tới để xem cái nào hoạt động tốt hơn cho kho lưu trữ và hệ thống của tôi và chấp nhận điều đó.
Aksel Willgert

8

Đừng giảm giá theo cách dễ dàng: nó có thể đủ nhanh cho mục đích của bạn. Với avfs để truy cập kho lưu trữ dưới dạng thư mục:

cd ~/.avfs/path/to/original.tar.gz\#
pax -w -s '/^.*\.jpg$//' | gzip >/path/to/filtered.tar.gz        # POSIX
tar -czf /path/to/filtered.tar.gz -s '/^.*\.jpg$//' .            # BSD
tar -czf /path/to/filtered.tar.gz --transform '/^.*\.jpg$//' .   # GNU

Với các công cụ nguyên thủy hơn, trước tiên hãy trích xuất các tệp trừ các .jpgtệp, sau đó tạo tệp lưu trữ mới.

mkdir tmpdir && cd tmpdir
<original.tar.gz gzip -d | pax -r -pe -s '/^.*\.jpg$//'
pax -w . | gzip >filtered.tar.gz
cd .. && rm -rf tmpdir

Nếu tar của bạn có --exclude:

mkdir tmpdir && cd tmpdir
tar -xzf original.tar.gz --exclude='*.jpg'
tar -czf filtered.tar.gz .
cd .. && rm -rf tmpdir

Tuy nhiên, điều này có thể mang quyền sở hữu tập tin và chế độ nếu bạn không chạy nó dưới quyền root. Để có kết quả tốt nhất, hãy sử dụng thư mục tạm thời trên hệ thống tệp nhanh - tmpfs nếu bạn có một thư mục đủ lớn.

Hỗ trợ cho các nhà lưu trữ hoạt động như một truyền qua (tức là đọc một kho lưu trữ và viết một kho lưu trữ) có xu hướng bị hạn chế. GNU tar có thể xóa các thành viên khỏi kho lưu trữ với --deletetùy chọn hoạt động ( --deleteTùy chọn đã được báo cáo là hoạt động chính xác khi tarhoạt động như một bộ lọc từ stdinđến stdout.,) Và đó có lẽ là tùy chọn tốt nhất của bạn.

Bạn có thể tạo các bộ lọc lưu trữ mạnh mẽ trong một vài dòng Python. tarfileThư viện của nó có thể đọc và viết từ các luồng không thể tìm kiếm và bạn có thể sử dụng mã tùy ý trong Python để lọc, đổi tên, sửa đổi

#!/usr/bin/python
import re, sys, tarfile
source = tarfile.open(fileobj=sys.stdin, mode='r|*')
dest = tarfile.open(fileobj=sys.stdout, mode='w|gz')
for member in source:
    if not (member.isreg() and re.match(r'.*\.jpg\Z', member.name)):
        sys.stderr.write(member.name + '\n')
        dest.addfile(member, source.extractfile(member))
dest.close()

Nó cũng sẽ mangle uid / tên người dùng nếu chạy bằng root trừ khi nó được thực hiện trên một máy có cùng ánh xạ tên người dùng <=> như là nơi mà tệp tar ban đầu được tạo. ACL, thuộc tính mở rộng cũng có thể bị ảnh hưởng. Với tar, bạn có thể muốn thêm ptùy chọn.
Stéphane Chazelas

2

Với tar có trên Mac OSX, bạn có thể làm điều này:

tar -czf b.tgz --exclude '*.jpg' @a.tgz
mv b.tgz a.tgz

1

Để làm điều này, có lẽ bạn phải trích xuất tất cả các phần tử của tệp .tgz trong một thư mục cục bộ sau đó xóa các tệp bạn không muốn sau đó giải nén lại .tgz.

Nó dài và bạn cần không gian đĩa trống đầy đủ nhưng theo hiểu biết tốt nhất của tôi, không có cách nào khác để làm điều đó.

Cho rằng bạn đã có một số đường dẫn /tmpdir/withalotofspacecó không gian trống đầy đủ (kiểm tra nó bằng cách sử dụng df -h /tmpdir/withalotofspace), bạn có thể làm một cái gì đó như thế này:

$ cd /tmpdir/withalotofspace
$ tar -xvfz /path/to/compressedArchive.tgz
$ find /tmpdir/withalotofspace/ -type f -iname '*.jpg' -delete
$ tar -cvzf /path/to/purgedcompressedArchive.tgz .

Như các câu trả lời khác cho thấy, thông qua đường ống, không cần lưu trữ dữ liệu không nén trên đĩa tại bất kỳ thời điểm nào
Tobias Kienzler

0

Tôi thích câu trả lời của @Gilles, ngoại trừ nó có thể được đơn giản hóa hơn nữa. Sau khi giải nén, ví dụ gunzip foo.tgztệp sẽ được foo.tarvà các tệp có thể được gỡ bỏ bằng tar -f foo.tar --delete file|directory. Dưới đây là một ví dụ về việc loại bỏ một thư mục từ một tập tin tar.

    phablet@ubuntu-phablet:~/Downloads$ tar -cvf moo.tar moo1/
    moo1/
    moo1/moo2/
    moo1/moo2/moo3/
    moo1/moo2/moo3/moo4/
    moo1/moo2/moo3/moo4/moo5/
    phablet@ubuntu-phablet:~/Downloads$ tar -tf moo.tar 
    moo1/
    moo1/moo2/
    moo1/moo2/moo3/
    moo1/moo2/moo3/moo4/
    moo1/moo2/moo3/moo4/moo5/
    phablet@ubuntu-phablet:~/Downloads$ tar -f moo.tar --delete "moo1/moo2/moo3"
    phablet@ubuntu-phablet:~/Downloads$ tar -tf moo.tar 
    moo1/
    moo1/moo2/

Các loại tập tin cụ thể có thể được tìm thấy với tar -tf foo.tar|egrep -i '.jpg$'.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.