Làm cách nào tôi có thể lọc nội dung của tệp tar, tạo tệp tar khác trong đường ống?


13

Hãy xem xét một tệp tar duy nhất từ ​​một hệ thống bên ngoài có chứa một số thư mục với các thuộc tính khác nhau mà tôi muốn giữ lại như quyền, mtimes, v.v ... Làm cách nào tôi có thể dễ dàng lấy một tập hợp con của các tệp này như một người dùng thông thường (không phải root)?

Tìm kiếm một cái gì đó như:

tar -f some.tar.gz --subset subdir/ | ssh remote@system tar xvz

Điều cũng cần thiết là các thuộc tính chính (quyền sở hữu, nhóm, chế độ, mtime) trong kho lưu trữ tar này được giữ lại. Còn các thuộc tính khác trong tệp tar như từ khóa tiêu đề mở rộng thì sao?

Điểm thưởng cho một giải pháp tránh sử dụng thư mục tạm thời trong trường hợp thư mục con này chứa các tệp lớn.

Câu trả lời:


14

bsdtar (dựa trên libarchive) có thể lọc tar (và một số tài liệu lưu trữ khác) từ stdin đến stdout. Ví dụ, nó chỉ có thể đi qua tên tệp khớp với một mẫu và có thể s/old/new/đổi tên. Nó đã được đóng gói cho hầu hết các bản phát hành, ví dụ như bsdtartrong Ubuntu.

sudo apt-get install bsdtar   # or aptitude, if you have it.

# example from the man page:
bsdtar -c -f new.tar --include='*foo*' @old.tgz
#create new.tar containing only entries from old.tgz containing the string ‘foo’
bsdtar -czf - --include='*foo*' @-  # filter stdin to stdout, with gzip compression of output.

Lưu ý rằng có nhiều lựa chọn định dạng nén cho đầu vào / đầu ra, vì vậy bạn không phải tự mình chuyển qua gunzip / lz4. Bạn có thể sử dụng -cho stdin với @tarfilecú pháp và / hoặc -cho thiết bị xuất chuẩn như bình thường.


Tìm kiếm của tôi cũng tìm thấy công cụ sửa đổi tar streaming này dường như muốn bạn xác định các thay đổi lưu trữ mà bạn muốn bằng cách sử dụng javascript. (Tôi nghĩ rằng toàn bộ điều được viết bằng js).

https://github.com/mafffy/tar-stream


1
Tuyệt vời, không biết rằng @original.tarphương pháp này là có thể với bsdtar. Có vẻ như cũng hoạt động với các thuộc tính mở rộng và nén, </var/cache/pacman/pkg/libuv-1.7.0-1-x86_64.pkg.tar.xz bsdtar -czf - --include='usr/share/*' @- | tar tvz(và vì một số lý do, một lựa chọn trống tạo ra một chuỗi các byte bằng 0, nhưng đó không phải là vấn đề lớn đối với tôi).
Lekensteyn

1
Theo thử nghiệm của tôi, s/old/new/ không hoạt động trên các tệp đến từ kho lưu trữ cũ bằng cách sử dụng @ old.tgz, nó chỉ hoạt động trên các tệp thực, lưu trữ trực tiếp từ hệ thống tệp. Thật đáng xấu hổ, vì nó sẽ là trường hợp sử dụng hữu ích nhất đối với tôi.
bart

4

Cách dễ nhất sẽ là sao chép toàn bộ kho lưu trữ; Tôi đoán bạn không muốn làm điều đó vì nó quá lớn.

Các công cụ dòng lệnh thông thường ( tar, pax) không hỗ trợ sao chép các thành viên của kho lưu trữ sang kho lưu trữ khác.

Nếu bạn không cần giữ quyền sở hữu, tôi khuyên bạn nên sử dụng các hệ thống tập tin FUSE . Bạn có thể sử dụng archivemount để gắn kết một kho lưu trữ như một hệ thống tập tin; làm điều này cho kho lưu trữ nguồn và chạy tar trên hệ thống tập tin được gắn kết.

archivemount some.tar.gz mnt
cd mnt
tar -cz subdir | ssh example.com tar -xz
fusermount -u mnt

Ngoài ra, bạn có thể sử dụng AVFS :

mountavfs
cd ~/.avfs$PWD/some.tar.gz\#
tar -cz subdir | ssh example.com tar -xz

Ngoài ra, bạn có thể chạy tartrên kho lưu trữ ban đầu và giải nén vào máy từ xa qua SSHFS .

sshfs example.com: mnt
cd mnt
tar -xf /path/to/some.tar.gz subdir
fusermount -u mnt

Tuy nhiên tất cả các phương pháp này đều cồng kềnh nếu bạn cần giữ quyền sở hữu. Tất cả đều liên quan đến việc trích xuất một tệp trên máy cục bộ, vì vậy quyền sở hữu của tệp này sẽ phải là quyền sở hữu từ xa dự định . Điều này yêu cầu chạy dưới quyền root và có thể không cho kết quả như mong muốn nếu các tệp được sở hữu bởi các tài khoản có tên hoặc ID khác nhau giữa máy cục bộ và máy chủ từ xa.

tarfileThư viện của Python cung cấp một cách khá dễ dàng để thao tác các thành viên tar, vì vậy bạn có thể xáo trộn chúng từ tệp tar này sang tệp tar khác. Nó hỗ trợ các định dạng chuẩn POSIX (ustar, pax) cũng như một số phần mở rộng GNU. Đây là tập lệnh Python chưa được kiểm tra đọc tệp tar (có thể được nén bằng gzip hoặc bzip2) trên đầu vào tiêu chuẩn của nó và ghi tệp tar được nén bằng bzip2 trên đầu ra tiêu chuẩn của nó. Các thành viên từ nguồn được sao chép nếu họ bắt đầu với đối số được truyền cho tập lệnh.

#!/usr/bin/env python2
import sys, tarfile
source = tarfile.open(fileobj=sys.stdin)
destination = tarfile.open(fileobj=sys.stdout, mode='w:bz2')
for info in source:
    if info.name.startswith(sys.argv[1]):
        destination.addfile(info)
destination.close()

Được gọi là

tar_filter <some.tar.gz subdir/ | ssh example.com tar -xj

1
bsdtar (dựa trên libarchive) có thể lọc lưu trữ tar khi đang di chuyển, xem câu trả lời của tôi.
Peter Cordes

Nhiệm vụ là trích xuất dữ liệu từ hình ảnh phần sụn, vì vậy quyền sở hữu / thành viên nhóm thực sự quan trọng. Cách tiếp cận python có thể làm việc mặc dù.
Lekensteyn

0

Một cách tiếp cận không có đặc quyền khác là sử dụng fakerootchương trình để giả vờ rằng bạn được phép thay đổi quyền sở hữu. Trong khi các thuộc tính tar khác bị mất, nó vẫn giữ chế độ, mtime và uid / gid. Các lệnh này tạo một thư mục tạm thời, trích xuất một tập hợp con của các tệp và cuối cùng tạo một kho lưu trữ mới:

mkdir tmp
<some.tar.gz \
fakeroot -- sh -c 'cd tmp && tar -xzf- subdir/ && tar -czf- subdir' |
   ssh remote@system tar -xzvf-
rm -rf tmp

0

GNU tarcó một --deletetùy chọn:

$ tar -c a b c | tar --delete a | tar -t
b
c

Bằng cách này, bạn có thể nhận được một tập hợp con của tar đầu vào bằng cách chỉ định những gì không bao gồm trong đầu ra.

Thật không may, tôi không thể có --excludetùy chọn để làm việc cùng --delete, vì vậy có vẻ như trước tiên bạn cần có một danh sách rõ ràng ( -t) những thứ cần xóa và sau đó chuyển nó sang một lời mời khác tar.

$ tar --delete --no-recursion `tar -t --exclude subdir <some.tar` <some.tar | ssh ...

Hoặc bạn có thể lưu trữ danh sách trong một tệp bên ngoài nếu nó quá dài hoặc phức tạp:

$ tar -t --exclude subdir <some.tar >to_delete.lst
$ tar --delete --no-recursion -T to_delete.lst <some.tar | ssh ...

-1

Từ những gì tôi biết, tarlệnh không thể sử dụng định dạng tar cả đầu vào và đầu ra. Bạn sẽ phải trích xuất các tệp cục bộ của mình bằng cách nào đó và sử dụng tar một lần nữa để tạo một tarfile khi đang di chuyển, với một cái gì đó như thế này ( -có nghĩa là đầu vào / đầu ra nổi bật được sử dụng thay vì một tệp):

tar cf - subdir/ | ssh remote@system 'cd extractdir && tar xvf -'

Lưu ý rằng việc có tarthể trích xuất một tarfile trực tiếp trong một tarfile khác là một ý tưởng thú vị ...


Nếu không có root, nó sẽ mất tất cả thông tin sở hữu / nhóm mà tôi rõ ràng muốn giữ.
Lekensteyn

1
Bạn nên chỉnh sửa câu hỏi của mình để bao gồm rằng bạn không có quyền truy cập root trên máy chủ của mình.
Uriel
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.