Spakować wszystkie pliki w katalogu?

482

Czy istnieje sposób na skompresowanie wszystkich plików w danym katalogu za pomocą zippolecenia? Słyszałem o używaniu *.*, ale chcę, aby działał również dla plików bez rozszerzeń.

tkbx
źródło
2
Czy próbowałeś nawigować o jeden poziom wyżej od wybranego katalogu i robisz zip myarch.zip mydir/*?
Joseph R.
13
lub lepiejzip -r myarch.zip mydir/*
Adam
25
lub lepiejzip -r myarch.zip mydir
ctrl-alt-delor
*.*oznacza dowolny plik z kropką. W cp / m i dos wszystkie pliki miały kropkę, co spowodowało, że wpisałeś (nie można tego zrobić *). Dlatego ludzie zaczęli widzieć *.*wszystkie pliki. W końcu Microsoft dodał długie nazwy plików, które mogą mieć zero lub więcej kropek. Aby znaleźć plik z kropką w systemie Windows, musisz wpisać *.*.*.
ctrl-alt-delor

Odpowiedzi:

704

Możesz po prostu użyć *; nie ma takiej potrzeby *.*. Rozszerzenia plików nie są wyjątkowe w Uniksie. *dopasowuje zero lub więcej znaków - w tym kropkę. Więc pasuje foo.png, ponieważ to zero lub więcej znaków (dokładnie siedem).

Zauważ, że *domyślnie pliki nie zaczynają się od kropki (również nie *.*). To jest często to, czego chcesz. Jeśli nie, w bash, jeśli shopt -s dotglobto zrobisz (ale nadal będzie wykluczać .i ..). Inne powłoki mają różne sposoby (lub wcale nie obejmują) plików kropkowych.

Alternatywnie, zipma również -ropcję (rekurencyjną) do robienia całych drzew katalogów jednocześnie (i nie musisz martwić się o problem z plikiem kropkowym):

zip -r myfiles.zip mydir

gdzie mydirjest katalog zawierający twoje pliki. Zauważ, że utworzony zip będzie zawierał zarówno strukturę katalogów, jak i pliki. Jak zauważa Peter w swoim komentarzu, jest to zwykle postrzegane jako dobra rzecz: rozpakowanie zip zachowa wszystkie wyodrębnione pliki w jednym podkatalogu.

Możesz także powiedzieć zipowi, aby nie zapisywał ścieżek za pomocą opcji -j/ --junk-paths.

zipPolecenie pochodzi z dokumentacji informujący o wszystkich swoich (wiele opcji); wpisz, man zipaby zobaczyć tę dokumentację. Nie jest to unikalne dla zip; w ten sposób można uzyskać dokumentację dla większości poleceń.

derobert
źródło
9
Możesz dodać, że dobrą praktyką jest przechowywanie wszystkiego w archiwum w katalogu najwyższego poziomu - aby nie zanieczyszczać jego / jej bieżącego katalogu podczas rozpakowywania.
peterph
@peterph gotowe. Chociaż jest to mniej konwencja w plikach zip niż np. W plikach tar, obawiam się.
derobert
Niestety tak. Prawdopodobnie ze względu na dziedzictwo Windows drag'n'drop na pulpit i dziedzictwo Linuksa pracy z kodami źródłowymi.
peterph
2
Należy pamiętać, że *globowanie powłoki nie obejmuje plików dot (tj. Nazw plików rozpoczynających się od .). Jest to kolejna zaleta spakowania całego katalogu według nazwy.
mrb
Ale użycie -r obejmuje sam katalog, co psuje to, co robię. Czy * nie obejmowałby .i ..?
tkbx
11

W moim przypadku chciałem spakować każdy plik do jego własnego archiwum, więc zrobiłem (in zsh):

$ for file in *; do zip ${file%.*}.zip $file; done
Radon Rosborough
źródło
1
Nie ma mkvtutaj? Również tutaj nic nie jest szczególnie zshspecyficzne. Będziesz chciał poprawnie cytować dowolną zmienną zawierającą nazwę pliku, więc zip "${file%.*}.zip" "$file"z podwójnymi cudzysłowami wokół obu zmiennych.
tripleee
1
@tripleee Po pierwsze, dziękuję za wskazanie mojego błędnego odniesienia do mkv. Po drugie, cytowanie argumentów jest niepotrzebne w zshprzeciwieństwie do bash. Właśnie dlatego podałem, że to było polecenie zsh.
Radon Rosborough,
Zastąpienie ostatniego średnika średnikiem znakiem ampersand może znacznie go przyspieszyć (jeśli liczba plików w katalogu jest rozsądna ...). W przeciwnym razie find . -type f -maxdepth 1 -print0|xargs -r0 -n1 -P64 -I{} bash -c 'f="{}"; zip "${f%.*}.zip" "$f"'(z -Pdostosowaniem w zależności od wątków procesora ...) (Wiele zależności GNU ...)
Gert van den Berg
5

Innym sposobem może być użycie find i xargs: (może to zawierać katalog „.” W pliku zip, ale nadal powinien być wypakowany poprawnie. Za pomocą mojego testu zip usunął kropkę przed kompresją) find . -type f -exec zip zipfile.zip {} +

( +Można zastąpić, \;jeśli twoja wersja findnie obsługuje +końca dla exec. Będzie jednak wolniejsza ...)

Obejmuje to domyślnie wszystkie podkatalogi. Na GNU find -maxdepthmoże temu zapobiec.

Gert van den Berg
źródło
(w przeciwieństwie do używanych rozwiązań *, będzie to obejmować pliki kropkowe i nie przewróci się, jeśli w katalogu będzie zbyt wiele plików)
Gert van den Berg
1

Inna (powolna) metoda, aby to zrobić (która dodaje jeden plik do zipu na raz):

for f in * .[^.]*; do
    [ -r "$f" ] || continue # Skip directories or non-existant files (Probably ".[^.]*" if directory has no dotfiles). Using -e will allow directories to be used as well
    zip zipfile.zip "$f" # If directories are included, you probably want to add -r
done

Ma to problemy z plikiem kropkowym *(dodane obejście) i byłby uruchamiany zip raz dla każdego pliku, dodając go do archiwum. W bash, poradziłby sobie z dużą ilością plików.

Byłby wolniejszy niż większość innych metod, ale jest stosunkowo prosty.

Gert van den Berg
źródło
1
Powiedziałbym, że jest to mniej proste niż zaakceptowana odpowiedź i wolniejsze, co powoduje pytanie: „Dlaczego ktoś miałby to robić?”. Jeśli potrafisz odpowiedzieć na to pytanie, zalecamy umieszczenie tego kontekstu w swojej odpowiedzi, w przeciwnym razie uważam, że jest to zła odpowiedź na stare pytanie, które ma już dobrą odpowiedź.
Centimane
@Centimane: Zwracam uwagę na ograniczenia. Uważam, że ma to wartość edukacyjną. (Jeśli nie pomijanie katalogów, jest to dość proste). Jeśli zamiast tego chcesz uzyskać znacznie szybszą odpowiedź przy użyciu (standardowego) narzędzia zewnętrznego, moja inna odpowiedź to obejmuje . (po usunięciu obsługi plików dotfiles (co wpływa na poprawność bez ich braku, o której mowa w pytaniu), czuję, że jest dość elegancki):for f in *; do zip zip.zip "$f"; done
Gert van den Berg
1
Zauważ, że zaakceptowana odpowiedź nie korzysta z zewnętrznego polecenia i byłaby szybsza. W jakim scenariuszu przydatna byłaby ta odpowiedź?
Centimane
@Centimane Z tar, gdy jest więcej plików, niż bash może przekazać jako parametry. (find + xargs są lepsze, ponieważ pętle są łatwiejsze ...). Jest to (unikalna) odpowiedź na pytanie. Z pewnością nie jest to optymalna odpowiedź. (Nieoptymalne odpowiedzi mogą być nadal przydatne w przypadku podobnych problemów, jeśli ktoś ma nieco inną sytuację - np. Chce mieć pliki tar w tym katalogu)
Gert van den Berg