Jak skompresować wiele plików w wierszu poleceń?

16

Wybacz to najbardziej podstawowe pytanie, ale nie mogłem znaleźć bezpośredniej odpowiedzi ani prostego przykładu na wymianie stosu.

Załóżmy, że mam folder plików, który chciałbym skompresować do jednego pliku zip, który mogę udostępnić moim okropnym przyjaciołom z systemu Windows (w przeciwnym razie po prostu użyję tari skończę z tym). To wygląda tak:

.
├── file1.txt
├── file2.txt
├── file3.txt
├── file.jpg
└── test.jpg

Zakładając, że zipzainstalowałem:

sudo apt-get install zip

Rozumiem man zip, że pozwala mi to na użycie listy plików:

- @ listy plików. Jeśli lista plików jest określona jako - @ [Nie w systemie MacOS], zip pobiera listę plików wejściowych ze standardowego wejścia zamiast z wiersza poleceń. Na przykład,

          zip -@ foo

Więc stworzyłem, zip.lstktóry wygląda tak:

cat zip.lst

file1.txt
file2.txt
file3.txt
file.jpg
test.jpg

A teraz próbowałem:

zip -@ zip.lst

Ale nie zrobił nic poza utworzeniem pustej linii na konsoli. I mogę dalej naciskać, Entera to po prostu robi więcej pustych linii bez pozornego wykonania polecenia. Po kilku poszukiwaniach zdałem sobie sprawę, że muszę zakończyć wprowadzanie, naciskając Ctrl+D

Ale teraz pojawia się ten błąd:

    zip warning: missing end signature--probably not a zip file (did you
    zip warning: remember to use binary mode when you transferred it?)
    zip warning: (if you are trying to read a damaged archive try -F)

zip error: Zip file structure invalid (zip.lst)

Co!? Dlaczego moja prosta lista nie jest „prawidłową strukturą plików”? Wróć do instrukcji, aby uzyskać więcej informacji, i przyjmuję się bliżej:

Jeśli lista plików jest określona jako - @ ...

Więc próbuję bez -@, a to przynajmniej przetwarza go od razu, bez konieczności naciskania Ctrl+, Dale mam ten sam błąd .

Na szczęście znalazłem komentarz do odpowiedzi na prawie niezwiązane pytanie, które doprowadziło mnie do zrozumienia, że ​​muszę wyraźnie nazwać plik zip. Wystąpił błąd, ponieważ domyślnie próbował utworzyć plik zip o nazwie zip.lst. Ale ponieważ taka jest nazwa mojej listy, można by pomyśleć, że po prostu ją zastąpi, ale nie, w rzeczywistości próbowała ją zaktualizować. A ponieważ lista oczywiście nie jest plikiem zip, otrzymujemy błąd nieprawidłowej struktury pliku, a teraz jest jasne, dlaczego napisano „prawdopodobnie nie plik zip”. Więc próbowałem:

zip files.zip zip.lst

adding: zip.lst (deflated 35%)

Eureka! Widzę, że plik zip został utworzony, a mój folder zawiera teraz:

.
├── file1.txt
├── file2.txt
├── file3.txt
├── file.jpg
├── files.zip
├── test.jpg
└── zip.lst

Ale poczekaj, zanim będziemy świętować, najpierw potwierdź zawartość pliku zip:

unzip -l files.zip

Archive:  files.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
       48  2016-05-24 15:30   zip.lst
---------                     -------
       48                     1 file

Nie! Właściwie to ma sens ze standardowego użycia, ponieważ po prostu spakowałem jeden plik listy, który mu dałem. W końcu spróbowałem ponownie, -@ale uzyskałem ten sam wynik.

Co ja robię źle?

BTW, wiem, że mogę korzystać z GUI i robić to za pomocą myszki, ale muszę to napisać, i ogólnie jestem szybszy na CLI, kiedy wiem, co robię.

Jeff Puckett
źródło

Odpowiedzi:

23

Użyj <przekierowania pliku

zip files.zip -@ < zip.lst

Lub możesz pominąć listę i po prostu glob

zip files.zip *.txt *.jpg

dzięki steeldriver

Odpowiedź historyczna

Cieszę się, że mogę odpowiedzieć na moje własne pytanie, ponieważ chciałem opowiedzieć o moich zawirowaniach w nadziei, że innym osobom podążającym za mną śladami łez uda się zaoszczędzić, wyszukując kilka słów kluczowych.

W końcu znalazłem właściwą odpowiedź , ale została wysłana na złe pytanie .

Kilka punktów jasności:

  • Instrukcja nie odnosi się do literalnej listy jak w pliku, ale raczej dosłownie do wyświetlania plików na konsoli.
  • Zrozumiałe jest, że ktoś może zostać wprowadzony w błąd, że fooodnosi się do listy plików, ale tak naprawdę ma reprezentować nazwę wyjściowego pliku zip.
  • Lista plików została pominięta w tym przykładzie, ponieważ używa -@przełącznika, który pokazuje, że „pobiera listę plików wejściowych ze standardowego wejścia zamiast z wiersza poleceń

Rozumiejąc to, jesteśmy teraz uzbrojeni na wiele sposobów, aby osiągnąć cel.

Po pierwsze, korzystając z utworzonej przez nas listy plików, możemy odczytać listę cati przekierować dane wyjściowe za pomocą potoku jako standardowego wejścia do zip:

cat zip.lst | zip -@ files.zip

  adding: file1.txt (stored 0%)
  adding: file2.txt (stored 0%)
  adding: file3.txt (stored 0%)
  adding: file.jpg (stored 0%)
  adding: test.jpg (stored 0%)

Widząc, że adding: ...dla każdego pliku jest to z pewnością dobry znak, ale mieliśmy już nadzieję, więc potwierdźmy:

unzip -l files.zip

Archive:  files.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
        0  2016-05-24 14:54   file1.txt
        0  2016-05-24 14:54   file2.txt
        0  2016-05-24 14:54   file3.txt
        0  2016-05-24 15:00   file.jpg
        0  2016-05-24 14:59   test.jpg
---------                     -------
        0                     5 files

SŁODKIE! Ale kto chce utworzyć listę jednorazowego użytku? To okropny sposób na rozwiązanie tego konkretnego scenariusza. Lepiej byłoby uzyskać listę lsi przesłać ją do zip:

ls | zip -@ files.zip

  adding: file1.txt (stored 0%)
  adding: file2.txt (stored 0%)
  adding: file3.txt (stored 0%)
  adding: file.jpg (stored 0%)
  adding: test.jpg (stored 0%)

Fantastyczny! Teraz stwórzmy filtry z niesamowitą mocą, grepaby po prostu spakować pliki jpg na przykład:

ls | grep .jpg | zip -@ images.zip

  adding: file.jpg (stored 0%)
  adding: test.jpg (stored 0%)

Lub po prostu pliki zaczynające się od „file”

ls | grep file. | zip -@ files.zip

  adding: file1.txt (stored 0%)
  adding: file2.txt (stored 0%)
  adding: file3.txt (stored 0%)
  adding: file.jpg (stored 0%)
Jeff Puckett
źródło
5
Zamiast używać lsi grepi zip -@, możesz użyć globusów powłoki, aby wybrać pliki bezpośrednio w linii poleceń zip np . zip files.zip file*Lub zip images.zip *.jpg. Ponadto, korzystając z listy nazw plików z pliku, można użyć przekierowania zamiast wywoływać osobny proces cat,zip files.zip -@ < zip.lst
steeldriver
Jak możesz sprawić, by działało to z zagnieżdżonymi katalogami obok plików?
BallpointBen,
@BallpointBen Użyłbym findzamiastls
Jeff Puckett
6

najprostsze polecenie z maksymalnym poziomem kompresji

zip -9 -r filename.zip /path/to/dir singlefile.jpg 
Ansyori
źródło