Giải nén các tập tin đang bay qua một đường ống


39

Tôi có thể giải nén hoặc bất kỳ chương trình tương tự nào hoạt động trên đầu ra tiêu chuẩn không? Tình huống là tôi đang tải xuống một tệp zip, được cho là giải nén nhanh chóng.

Vấn đề liên quan: Làm cách nào để chuyển một tệp đã tải xuống thành đầu ra tiêu chuẩn trong bash?


Điều này có vẻ như là có thể thực hiện được, nhưng có vẻ như chỉ có thể trích xuất một zip và chuyển tệp sang một lệnh khác nếu zip chỉ chứa một tệp duy nhất. Tôi muốn trích xuất một tập tin cụ thể từ một zip nhiều tập tin. Thay vì đường ống, tôi chuyển sang xâu chuỗi nhiều tệp 'unzip file.zip / path / file && do ware / path / file && rm -rf / path' Trong khi không trả lời câu hỏi ban đầu và kết quả là các tệp tạm thời được tạo nhu cầu.
Stan Kurdziel

Kiểm tra pigz. Chúng tôi sử dụng nó trong một đường ống. andrew.tumblr.com/post/2316602611
dmourati

Câu trả lời:


22

Mặc dù tệp zip thực tế là định dạng chứa, không có lý do nào khiến nó không thể được đọc từ một đường ống (stdin) nếu tệp có thể vừa với bộ nhớ đủ dễ dàng. Đây là tập lệnh Python lấy tệp zip làm đầu vào tiêu chuẩn và trích xuất nội dung vào thư mục hiện tại hoặc vào thư mục được chỉ định nếu được chỉ định.

import zipfile
import sys
import StringIO
data = StringIO.StringIO(sys.stdin.read())
z = zipfile.ZipFile(data)
dest = sys.argv[1] if len(sys.argv) == 2 else '.'
z.extractall(dest)

Kịch bản này có thể được thu nhỏ thành một dòng và được tạo thành bí danh.

alias unzip-stdin="python -c \"import zipfile,sys,StringIO;zipfile.ZipFile(StringIO.StringIO(sys.stdin.read())).extractall(sys.argv[1] if len(sys.argv) == 2 else '.')\""

Bây giờ giải nén đầu ra của wget dễ dàng.

wget http://your.domain.com/your/file.zip -O - | unzip-stdin target_dir

1
Bạn và trăn đá !!!
Farid Nouri Neshat

3
Một lớp lót đẹp và +1 để đề cập rằng tệp phải vừa với bộ nhớ. (Rất tiếc, không có cách nào để giải nén tệp pkzip do cấu trúc định dạng tệp).
lxgr

2
hãy ghi nhớ bộ đệm này mọi thứ trong bộ nhớ trước khi giải nén
William Casarin

1
không có lý do tại sao nó không thể được đọc dưới dạng luồng nếu tệp có thể vừa với bộ nhớ một cách dễ dàng, không thực sự chính xác. Lý do tại sao bạn buộc phải đệm toàn bộ kho lưu trữ zip trong bộ nhớ trước khi bạn trích xuất nội dung cụ thể là vì nó không thể được đọc dưới dạng luồng. Tất nhiên, vẫn có thể hữu ích để tránh ghi tệp lưu trữ zip vào một tệp.
Håkan Lindqvist

Đây không phải là một luồng, bạn đang đọc toàn bộ tệp trong bộ nhớ bằng cách sử dụng .read()phương thức
Romuald Brunet

17

Điều này không có khả năng làm việc như bạn mong đợi. Zip không chỉ là một định dạng nén, mà còn là một định dạng chứa. Nó cuộn các công việc của cả tar và gzip.bzip2 thành một. Phải nói rằng, nếu zip của bạn có một tệp duy nhất, bạn có thể sử dụng giải nén -p để giải nén các tệp vào thiết bị xuất chuẩn. Nếu bạn có nhiều hơn một tệp, không có cách nào để bạn biết nơi chúng bắt đầu và dừng lại.

Đối với việc đọc từ stdin, trang man giải nén có câu này:

Lưu trữ đọc từ đầu vào tiêu chuẩn chưa được hỗ trợ, ngoại trừ với funzip (và sau đó chỉ có thể trích xuất thành viên đầu tiên của kho lưu trữ).

Bạn có thể có một số may mắn với funzip.


Nếu zip có nhiều tệp bên trong, thì -p có thể in ra một tệp bằng cách sử dụng tên tệp làm tham số: unzip -p temp.zip tệp-bên trong zip
Taavi Ilves

7

Những gì bạn muốn làm là, hãy unziplấy một tệp ZIPped trên đầu vào tiêu chuẩn của nó chứ không phải là một đối số. Điều này thường dễ dàng được hỗ trợ bởi gziptarloại công cụ với một -đối số. Nhưng tiêu chuẩn unzipkhông làm điều đó (mặc dù, nó hỗ trợ khai thác vào đường ống). Tuy nhiên, tất cả là không bị mất...

Nhìn vào trang hướng dẫn funzip .

funzip không có đối số tập tin hoạt động như một bộ lọc; nghĩa là, nó giả định rằng một tệp lưu trữ ZIP (hoặc tệp gzip'd) đang được chuyển vào đầu vào tiêu chuẩn và nó trích xuất thành viên đầu tiên từ kho lưu trữ sang thiết bị xuất chuẩn. Khi stdin đến từ một thiết bị tty, funzip giả định rằng đây không thể là luồng dữ liệu nén (nhị phân) và thay vào đó hiển thị một văn bản trợ giúp ngắn. Nếu có một đối số tệp, thì đầu vào được đọc từ tệp được chỉ định thay vì từ stdin.

Với giới hạn về trích xuất một thành viên, funzip là hữu ích nhất khi kết hợp với chương trình lưu trữ thứ cấp như tar (1). Phần sau đây bao gồm một ví dụ minh họa việc sử dụng này trong trường hợp sao lưu đĩa vào băng.

Điều này phù hợp với ý tưởng rằng hầu hết các tài liệu lưu trữ linux thường được TAR'ed và sau đó được ZIP theo một cách nào đó (gzip, bzip, et al). Điều này sẽ làm việc cho bạn nếu bạn có một tar.ZIP.


Điều đáng chú ý funziplà được viết bởi tác giả gốc Info-ZIP Mark Adler. Ông viết trong trang người đàn ông funzip,

this functionality should be incorporated into unzip itself (future release).

tuy nhiên, không có cập nhật như vậy được nhìn thấy xung quanh. Tôi nghi ngờ rằng Mark thấy không cần thiết vì các phương pháp lưu trữ khác hoạt động dễ dàng với TAR.


Chỉ cần một nhận xét; một số người muốn python hoặc bất kỳ ngôn ngữ nào như là một tùy chọn để giải nén. Một ví dụ điển hình là Heroku không bao gồm tar hoặc giải nén trên hệ thống của nó. Một cách giải quyết là sử dụng jar bằng cách cài đặt Java được phép.
Nick

Có nhiều hơn về việc xử lý các hạn chế của funzip và các công cụ tương tự (đặc biệt là chỉ có khả năng hiển thị thành viên đầu tiên của kho lưu trữ) trong câu trả lời này: unix.stackexchange.com/a/211286/77539
Joshua Goldberg

6

Tôi thích sử dụng curl vì nó được cài đặt theo mặc định ( -Lcần thiết cho các chuyển hướng thường xảy ra):

curl -L http://example.com/file.zip | bsdtar -xvf - -C /path/to/directory/

Tuy nhiên, bsdtarkhông được cài đặt theo mặc định và tôi không thể funziplàm việc.


Cũng hoạt động tốt với nhiều tệp
jonnor

5

Đây là một bài đăng lại câu trả lời của tôi cho một câu hỏi tương tự:

Định dạng tệp ZIP bao gồm một thư mục (chỉ mục) ở cuối kho lưu trữ. Thư mục này cho biết vị trí, trong kho lưu trữ, mỗi tệp được đặt và do đó cho phép truy cập nhanh, ngẫu nhiên mà không cần đọc toàn bộ tệp lưu trữ.

Điều này có vẻ gây ra vấn đề khi cố đọc tệp lưu trữ ZIP qua đường ống, trong đó chỉ mục không được truy cập cho đến khi kết thúc và vì vậy các thành viên riêng lẻ không thể được trích xuất chính xác cho đến khi tệp đã được đọc hoàn toàn và không còn khả dụng . Do đó, có vẻ không ngạc nhiên khi hầu hết các bộ giải nén ZIP chỉ đơn giản là thất bại khi kho lưu trữ được cung cấp qua một đường ống.

Thư mục ở cuối kho lưu trữ không phải là vị trí duy nhất lưu trữ thông tin meta tệp trong kho lưu trữ. Ngoài ra, các mục riêng lẻ cũng bao gồm thông tin này trong tiêu đề tệp cục bộ, cho mục đích dự phòng.

Mặc dù không phải mọi trình giải nén ZIP sẽ sử dụng các tiêu đề tệp cục bộ khi chỉ mục không khả dụng, mặt trước tar và cpio kết thúc với libarchive (còn gọi là bsdtar và bsdcpio) có thể và sẽ làm như vậy khi đọc qua một ống, có nghĩa là có thể sau đây:

wget -qO- http://example.org/file.zip | bsdtar -xvf-

4

Info-Zip không thể thực hiện được, đây là cách triển khai OSS phổ biến nhất. Quan trọng hơn, mặc dù vậy, nó không được khuyến khích do các cấu trúc của kho lưu trữ ZIP.

Nếu thay đổi định dạng là khả thi với bạn thì hãy xem xét sử dụng tar (1) thay thế. Nó khá hài lòng với đầu vào / đầu ra được truyền phát và trên thực tế, mong đợi nó theo mặc định.

Ngoài ra, bạn thường có thể biết liệu các ứng dụng có mong muốn đầu vào / đầu ra được truyền phát hay không bằng cách chỉ định "-" cho tên tệp. Info-Zip, như bạn có thể tưởng tượng, không coi đây là một đối số hợp lệ.


4

Trong zsh, bạn có thể làm như sau:

unzip =( curl http://example.com/someZipFile.zip )

3

Tiện ích phổ biến đơn giản nhất có sẵn sẽ làm điều này là jar, nó sẽ cho rằng STDIN đang được sử dụng nếu bạn vượt qua nó không có tệp nào tranh luận. Nó cũng có các đối số tương tự như tarchương trình cho các hoạt động.

ví dụ: liệt kê nội dung của một kho lưu trữ

curl https://my.example.com/file.zip | jar t

Mặc dù Java không phải lúc nào cũng được cài đặt, nhưng trên các máy đó, jarchắc chắn là phương pháp thuận tiện nhất để thực hiện việc này.


3

Đăng lại câu trả lời của tôi :

BusyBox unzipcó thể lấy stdin và giải nén tất cả các tệp.

wget -qO- http://downloads.wordpress.org/plugin/akismet.2.5.3.zip | busybox unzip -

Dấu gạch ngang sau unziplà sử dụng stdin làm đầu vào.

Bạn có thể,

cat file.zip | busybox unzip -

Nhưng đó chỉ là dư thừa unzip file.zip.

Nếu distro của bạn sử dụng BusyBox theo mặc định (ví dụ: Alpine), chỉ cần chạy unzip -.


1

Tôi thực sự cần một cái gì đó phức tạp hơn một chút - giải nén một tệp cụ thể nếu nó tồn tại. Khó khăn là, luồng tệp đầu vào có thể không phải là tệp zip và trong trường hợp đó, tôi cần nó để tiếp tục qua đường ống. Đây là giải pháp của tôi (chủ yếu nhờ vào giải pháp Jason R. Coombs)

python -c "import zipfile,sys,StringIO
data=sys.stdin.read()
try:
    z=zipfile.ZipFile(StringIO.StringIO(data))
    z.open(\"$1\")
    sys.stdout.write(z.read(\"$1\"))
except (RuntimeError, zipfile.BadZipfile):
    sys.stdout.write(data)"

Tôi đã lưu tệp này dưới dạng tệp có tên "effpoptp" (không phải tên đơn giản) trong thư mục "/ bin" trên máy của mình để kiểm tra nó giống như vậy:

cat defaultModel.mwb|effpoptp "document.mwb.xml"

Mục đích là để kiểm soát phiên bản các tệp MySQL Workbench, trong đó tệp có thể là tệp xml có tên là tệp bàn làm việc hoặc tệp bàn làm việc hoàn chỉnh.

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.