Rura B do D? - A i&B || C | re

14

Czy istnieje sposób, aby ponownie napisać strukturę poleceń, A && B || C | Daby B lub C zostały podłączone do D?

Przy bieżącym poleceniu uruchamiane są tylko B lub oba C i D.

Na przykład:

wprowadź opis zdjęcia tutaj

Philip Kirkbride
źródło

Odpowiedzi:

31

Tak, w bash możesz użyć nawiasów:

(A && B || C) | D

W ten sposób wyjście A && B || Czostanie przekazane do D.

utopiabound
źródło
6
Lub A && (B || C) | D, jeśli nie chcesz, aby B, C lub D działały, gdy A zawiedzie
zwolnij
2
Możesz także użyć parens w sh:)
EKons
Nie jest jasne, czy stosowanie nawiasów zamiast nawiasów klamrowych było zamierzoną decyzją (jeśli tak, jakie są korzyści?), Czy tylko przeoczeniem. Czy możesz wytłumaczyć?
Tom Fenech 18.04.17
@TomFenech Parens powodują, że wyrażenie działa w podpowłoce, która jest (pojedynczym) procesem odrębnym od POV reszty skryptu. Dlatego niezależnie od wyniku wyrażenia w parens, zostanie ono połączone. (Ponieważ Aznajduje się w podpowłoce, obejmuje to również A.)
jpaugh 18.04.17
1
@jpaugh Myślę, że twój punkt na temat izolacji jest dobry, ale wynik byłby przesyłany w ten sam sposób, gdy używasz nawiasów klamrowych, prawda?
Tom Fenech 18.04.17
14

Możesz to napisać jako

if A; then B; else C; fi | D

Mówisz, że chcesz uruchomić albo Balbo C, ale A && B || Cnie osiągnąć. Jeśli się Apowiedzie, ale Buruchomi się i nie powiedzie, wykona się C.

Uwaga 1: jeśli możesz w jakiś sposób zagwarantować, że Bzawsze się powiedzie i chcesz pozostać przy krótkiej wersji, nadal bym wybrał

{ A && B || C; } | D

koniec ( ... ), ponieważ ten ostatni niepotrzebnie wymusza utworzenie nowej podpowłoki, która może, ale nie musi zostać zoptymalizowana.

Uwaga 2: zakładamy, że obie formy Anie generują danych wyjściowych, co jest prawdą w twoim przykładzie, ale niekoniecznie w ogóle. Można tego uniknąć

A; if [ "$?" -eq 0 ]; then B; else C; fi | D
hvd
źródło
Czy na pewno { … }nie wymusza to utworzenia podpowłoki z powodu potoku? I zaobserwować następujące zachowanie: pgrep bashi pgrep bash | cati if true; then pgrep bash; fii { pgrep bash; }mają jedną linię wyjścia; ( pgrep bash; )i ( pgrep bash; ) | cati { pgrep bash; } | cati if true; then pgrep bash; fi | catmają dwa wiersze wyników.
wchargin 18.04.17
@wchargin ... | ...powoduje utworzenie podpowłoki, co jest nieuniknione. ( ... ), przynajmniej teoretycznie, powoduje utworzenie dodatkowej podpowłoki, która { ...; }pozwala jej uniknąć, ale właśnie to miałem na myśli mówiąc „może zostać zoptymalizowany lub nie”: możliwe jest, że w tym konkretnym przypadku powłoka zdaje sobie sprawę, że to nie ma znaczenia, efekt byłby taki sam.
hvd
5

Odpowiedź akceptora jest poprawna, ale nie obejmuje potencjalnego przypadku użycia, którego nie należy podawać Ajako wyniku D. Aby to osiągnąć, konieczne będzie przekierowanie strumienia w Azależności od potrzeb.

  • Jeśli Amimo wszystko chcesz odrzucić dane wyjściowe :

    { A >/dev/null && B || C; } | D
  • Jeśli chcesz zobaczyć dane wyjściowe Ana terminalu:

    { A >/dev/tty && B || C; } | D
  • Jeśli potrzebujesz danych wyjściowych Ajako danych wejściowych kolejnego polecenia E, potrzebujesz dodatkowej grupy poleceń i przekierowania strumienia:

    { { A >&3 && B || C; } | D; } 3>&1 | E

Jeśli to wszystko wydaje się zbyt tajemnicze (tak jak dla mnie), zalecamy użycie specjalnej zmiennej powłoki dla statusu wyjścia Ai pracę z tym:

A
if [ $? -eq 0 ]; then
  B
else
  C
fi |
D

Jeśli chcesz być bardziej zwięzły, ale nie zbyt tajemniczy, sugeruję to:

A; { [ $? -eq 0 ] && B || C; } | D

(Zobacz także ostatnią część odpowiedzi hvd, której nie zauważyłem, kiedy napisałem swoją pierwotną odpowiedź).

David Foerster
źródło
Moja odpowiedź to obejmuje. Zobacz, co umieściłem w „Uwadze 2”, gdzie po prostu Awyszedłem z rurociągu.
hvd
@hvd: Masz rację i dziękuję za wskazanie mi tej części twojej odpowiedzi! Zmieniłem swoje roszczenie i odpowiednio podałem kredyt.
David Foerster