Dlaczego nie wszystkie pliki są skompresowane i jak poprawić rozwiązanie

8

Mam folder z około 20 000 plików. Pliki są nazywane zgodnie ze wzorem xy_{\d1,5}_{\d4}\.abc, np xy_12345_1234.abc. Chciałem skompresować pierwsze 10 KB z nich za pomocą tego polecenia:

ls | sort -n -k1.4,1.9 | head -n10000 | xargs tar -czf xy_0_10000.tar.gz

jednak plik wynikowy zawierał tylko około 2 KB plików.

ls | sort -n -k1.4,1.9 | head -n10000 | wc -l zwraca jednak 10000, zgodnie z oczekiwaniami.

Wydaje mi się, że nie rozumiem tutaj czegoś podstawowego ...

Używam zsh 5.0.2 na Linux Mint 17.1, GNU tar 1.27.1

EDYTOWAĆ:

rozwidlenie, jak sugeruje @Archemar, wydaje się bardzo prawdopodobne, z najnowszym rozwidleniem nadpisującym wynikowy plik - plik zawiera „ogon” plików - od 7773 do 9999 .

wynik xargs --show-limit: Your environment variables take up 3973 bytes POSIX upper limit on argument length (this system): 2091131 POSIX smallest allowable upper limit on argument length (all systems): 4096 Maximum length of command we could actually use: 2087158 Size of command buffer we are actually using: 131072

zastępując -cz -rlub -unie działa w moim przypadku. Komunikat o błędzie totar: Cannot update compressed archives

użycie obu -ri -ujest nieprawidłowe i kończy się niepowodzeniemtar: You may not specify more than one '-Acdtrux', '--delete' or '--test-label' option

zastępując -cze -awydaje się być nieważne jak dobrze i nie z tym samym tar: You must specify one of the '-Acdtrux', '--delete' or '--test-label' optionschociaż dont uznaję problem azfi Acdtruxwydaje dysjunktywnej do mnie.

EDYCJA 2:

-T wygląda jak dobry sposób, ja też znalazłem przykład tutaj .

Jednak kiedy spróbuję

ls | sort -n -k1.4,1.9 | head -n10000 | tar -czf xy_0_10000.tar.gz -T - dostaję tar: option requires an argument -- 'T'

cóż, może nazwy plików nie docierają do tar? Ale wygląda na to, że robią, bo kiedy wykonuję

ls | sort -n -k1.4,1.9 | head -n10000 | tar --null -czf xy_0_10000.tar.gz -T - dostaję tar: xy_0_.ab\nxy_1_...<the rest of filenames separated by literal \n>...998.ab Cannot stat: File name too long

Dlaczego więc tar nie widzi nazw plików?

kostja
źródło
a jeśli spróbujesz zamiast c, w poleceniu tar?
Olivier Dulac
5
Ważne: Nie analizuj wynikuls
8bittree,
1
Plik OP nie ma trudnych nazw.
Archemar
@ 8bittree - ogólna rada dotycząca niezawodnych skryptów powłoki, tak. ale co sugerujesz zamiast tego do pracy z listami plików ze zwykłymi jednorazowymi onelinerami?
kostja
1
@kostja użyłbym find, który ma -print0opcję użycia bajtu zerowego jako separatora zamiast nowego wiersza. sortporadzę sobie z tym z -zflagą. head, niestety nie obsługuje zrozumienia ograniczników null-bajtowych, ale ta odpowiedź ma rozwiązanie polegające trna zamianie \noraz \0przed i po head. tarmusi --null -T -odczytać nazwy plików rozdzielane znakami zerowymi stdin.
8bittree,

Odpowiedzi:

12

osiągnąłeś limit xargs?

xargs --show-limit

próbować :

  • utwórz .tgzplik fikcyjnytar czf xy_0_10000.tar.gz /hello/world
  • zastąpić -czfprzez -Azf

kiedy xarg osiągnie swój limit, rozwidli polecenie, więc było to polecenie, które ostatecznie wykonałeś

  tar czf xy_0_10000.tar.gz file1 file2 .... file666
  tar czf xy_0_10000.tar.gz file667 file668 ... file1203
  tar czf xy_0_10000.tar.gz file1024 ... file2000

ponieważ każda smoła wykracza poza poprzednią, możesz dostać tylko ostatni tar cbieg.

Edytować:

1) zgodnie z man tarunbuntu, -ai -r wydaje się, że równoważne dołączanie jest wykonywane przez (albo) -A, --catenate, --concatenate

2) zip(nie gzip) można użyć do dodania pliku, może załatwi go opcja gzip. (użyj | xargs zip -qr xy_0_0000.zip, spowoduje to utworzenie pliku zip, a nie pliku .tar.gz)

3) korzystanie z rozwiązania @ rsanchez
Ważne jest, aby dodać opcję tar w odpowiedni sposób, spróbuj

ls | sort -n -k1.4,1.9 | head -n10000 |tar -czf xy_0_10000.tar.gz -T -

gdzie - -T -oznacza opcję użycia -Ti użyj -jako argumentu do -T(możesz wygenerować listę plików /tmp/foo.lst, a następnie użyć -T /tmp/foo.lst)

Archemar
źródło
czy a (= dodaj) zamiast c (= tworzenie / nadpisywanie) może obejść to ograniczenie?
Olivier Dulac
@OlivierDulac ( Ostrzeżenie: to tylko zgadywanie ) Prawdopodobnie nie rozwiąże się, ponieważ tar nie może tworzyć pustych plików. Państwo może kompresować pusty folder pierwszy i używać a (add), aby dodać pliki do pliku tar. Następnie możesz otworzyć tar i usunąć folder (używając 7zipa lub czegoś takiego)
Ismael Miguel
@ismaelmiguel: Jestem pewien, że z radością utworzy plik. jeśli nie, po prostu:touch xy_0_10000.tar.gz && { _the full command here_ ; }
Olivier Dulac
1
@OlivierDulac To będzie nieprawidłowy .gzplik.
Ismael Miguel
Wszystkie strony, które widzę z manpages.ubuntu.com/manpages/vivid/en/man1/tar.1.html (15.04) z powrotem do dokładnych (12.04) mają -rdołączone, ale -aautomatyczne kompresowanie, które nie jest równoważne. I -rznie działa: zipmożna dodać do istniejącego archiwum, ponieważ katalog nie jest skompresowany, ale tarkompresja kompresuje metatdaty wraz z danymi. Możesz tar -rpodzielić się na nieskompresowane archiwum, a następnie spakować wynik. Lub ...
dave_thompson_085
12

Nie ma takiej potrzeby xargs. Jeśli bezpośrednio dać tarz -T -opcji będzie czytać nazwy plików ze standardowego wejścia.

Na przykład:

... | tar -T - -czf xy_0_10000.tar.gz
rsanchez
źródło
Wydaje mi się, że używam tej opcji niepoprawnie, nie mogę zmusić jej do pracy z potokiem. Próbowałem ...| tar Tczf xy_..., ...| tar Tcz -f xy_... ...| tar -czf xy_... -T i kilka innych permutacji, ale otrzymuję tylko tar: You must specify one of the '-Acdtrux', '--delete' or '--test-label' options, tar: -f: Cannot stat: No such file or directoryjeśli przy użyciu -foddzielnie od innych opcji i tar: option requires an argument -- 'T'. Czy możesz dodać przykład użycia?
kostja
Dodano przykład @kostja.
rsanchez
Wielkie dzięki, rsanchez. Nie jestem pewien, dlaczego wariant z -T -na końcu tarlisty opcji nie działał, ale twój przykład zadziałał. Niestety moje pytanie składało się z dwóch części - źródła błędu i możliwej poprawy. Podczas gdy pokonałeś drugiego, Archemar przodował w pierwszym i prawie miał drugie prawo. Nie jestem pewien, które z twoich odpowiedzi należy zaakceptować, ponieważ obie były oczywiście pomocne.
kostja
1

Chcę uzupełnić dwie pozostałe odpowiedzi rozwiązaniem zsh , które ani nie analizuje ls , ani nie potrzebuje xargs . Jednak nie jestem teraz pewien, czy cierpi to również z powodu ograniczenia długości linii poleceń.

  1. Zdefiniuj funkcję, która generuje pożądany klucz sortowania poprzez modyfikację $REPLY.

    sortkey() { REPLY=${REPLY[4,9]} }

    Jest to równoważne z twoim sort -n -k1.4,1.9

  2. Wygeneruj tablicę $filesz nazwami plików posortowanymi za pomocą powyższej funkcji:

    files=(*(o+sortkey))

    Jest to równoważne z ls | sort -n -k1.4,1.9

  3. Zwróć pierwsze 10 000 plików za pomocą

    ${files[0,9999]}

    Jest to równoważne z ls | sort -n -k1.4,1.9 | head -n10000

Podsumowując, powinno to załatwić sprawę:

sortkey() { REPLY=${REPLY[4,9]} }
files=(*(o+sortkey))
tar -czf xy_0_10000.tar.gz ${files[0,9999]}
mpy
źródło