tar do potoku, ale trzymaj -v pełne wyjście niezależnie od STDERR

12

Normalne polecenie tar

tar cvf foo.tar ./foo >foo.out 2>foo.err

ma trzy wyjściowe strumienie we / wy

  • zarchiwizuj dane na foo.tar
  • lista nazw plików do STDOUT (przekierowane do foo.out)
  • komunikaty o błędach do STDERR (przekierowane do foo.err)

Następnie mogę sprawdzić foo.err pod kątem komunikatów o błędach bez konieczności czytania listy nazw plików.

jeśli chcę coś zrobić z danymi archiwalnymi (przepuszczać przez netcat lub specjalny program do kompresji), mogę użyć -f -opcji tar

tar cvf - ./foo 2>foo.err | squish > foo.tar.S

Ale teraz moja lista nazw plików jest mieszana z moimi komunikatami o błędach, ponieważ -vdane wyjściowe tar oczywiście nie mogą przejść do STDOUT (tam, gdzie przepływają dane archiwalne), więc tar sprytnie zapisuje je do STDERR.

Za pomocą powłoki Korna istnieje sposób na zbudowanie polecenia, które potokuje strumień archiwum do innego polecenia, ale nadal przechwytuje dane -vwyjściowe niezależnie od komunikatów o błędach.

RedGrittyBrick
źródło
Czy znasz tee? Wydaje się, że jest to całkiem uzasadniony przypadek użycia.
HalosGhost

Odpowiedzi:

9

Jeśli twój system obsługuje /dev/fd/n:

tar cvf /dev/fd/3 ./foo 3>&1 > foo.out 2>foo.err | squish > foo.tar.S

Które z implementacjami AT&T ksh( bashlub zsh) możesz napisać za pomocą podstawienia procesu :

tar cvf >(squish > foo.tar.S) ./foo > foo.out 2>foo.err

Robi to dokładnie to samo, tyle że tym razem powłoka decyduje, którego deskryptora pliku użyć zamiast 3(zwykle powyżej 9). Kolejna różnica polega na tym, że tym razem tarzamiast statusu otrzymujesz status wyjścia squish. W systemach, które nie obsługują /dev/fd/n, niektóre powłoki mogą korzystać z nazwanych potoków dla tej funkcji.

Jeśli twój system nie obsługuje /dev/fd/nlub powłoka nie może użyć nazwanych potoków do zastąpienia procesu, wtedy musisz ręcznie poradzić sobie z nazwanymi potokami .

Stéphane Chazelas
źródło
6

W tym celu musisz użyć nazwanego potoku.

Najpierw utwórz go w folderze:

mkfifo foo.pipe

Następnie użyj tego polecenia:

tar cvf foo.pipe ./foo >foo.out 2>foo.err & cat foo.pipe >foo.tar

Wskazówka:cat -part, może być teraz także gzipczy cokolwiek innego, że może czytać z potoku:

tar cvf foo.pipe ./foo >foo.out 2>foo.err & gzip -c foo.pipe >foo.tar

Wyjaśnienie:

Wyjście jest napisane na rurze (nazwa foo.pipe), gdzie inny proccess ( cat, gzip, netcat) odczytuje z. Więc nie tracisz kanałów stdout / stderr dla informacji.

chaos
źródło
1
Być może warto zwrócić uwagę na konsekwencje używania nazwanych rur. 1) najlepiej jest ustawić umask 077(lub użyć prywatnego katalogu tymczasowego), aby uniemożliwić innym procesom odczytywanie lub zapisywanie w nim (w wielu systemach nazwane potoki, podobnie jak inne pliki są domyślnie tworzone do odczytu na świecie), 2) musisz zapewnić nazwany potok jest używany tylko przez każde wystąpienie skryptu (ponownie pomaga jednorazowy prywatny katalog tymczasowy) 3) Oznacza to, że musisz wyczyścić później lub jeśli zostanie przerwany.
Stéphane Chazelas
1
+1 - Podoba mi się ta odpowiedź. Na nieszczęście dla mnie, w moim (starym) systemie jest trochę dziwności w nazwanych potokach, co powoduje, że są one niewiarygodne, gdy próbuję tego.
RedGrittyBrick
1
@ StéphaneChazelas - Myślę, że czasem łatwiej jest najpierw posprzątać, na przykład:p="/tmp/pipe$$"; mkfifo "$p"; (read na; cmd[s]...) <>"$p" & (echo;rm "$p"; cmd[s]...) >"$p"
mikeserv
5

--index-fileOpcja GNU tar działa dobrze:

tar cvf - ./foo 2>foo.err --index-file=foo.out | squish > foo.tar.S
Josh Kelley
źródło