Ống B đến D? - A && B | | C | D


14

Có cách nào để viết lại cấu trúc lệnh A && B || C | Dsao cho B hoặc C được dẫn vào D không?

Với lệnh hiện tại, chỉ B hoặc cả C và D được chạy.

Ví dụ:

nhập mô tả hình ảnh ở đây

Câu trả lời:


31

Có, trong bash bạn có thể sử dụng dấu ngoặc đơn:

(A && B || C) | D

Bằng cách này, đầu ra của A && B || Csẽ được dẫn vào D.


6
Hoặc A && (B || C) | D, nếu bạn không muốn B, C hoặc D chạy khi A thất bại
zwol

2
Bạn cũng có thể sử dụng parens trong sh:)
EKons

Không rõ liệu sử dụng dấu ngoặc đơn thay cho dấu ngoặc nhọn là một quyết định có chủ ý (nếu vậy, lợi ích là gì?) Hay chỉ là một sự giám sát. Bạn có thể giải thích?
Tom Fenech

@TomFenech Parens làm cho biểu thức chạy trong lớp vỏ phụ, đây là một quá trình riêng biệt (đơn) từ POV của phần còn lại của tập lệnh. Do đó, bất kể đầu ra của biểu thức bên trong parens, nó sẽ được nối với nhau. (Vì Alà bên trong lớp vỏ, điều này cũng bao gồm A.)
jpaugh

1
@jpaugh Tôi nghĩ rằng quan điểm của bạn về sự cô lập là tốt nhưng đầu ra sẽ được xử lý theo cách tương tự khi sử dụng dấu ngoặc nhọn, phải không?
Tom Fenech

14

Bạn có thể viết cái này như

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

Bạn nói rằng bạn muốn chạy Bhoặc C, nhưng A && B || Ckhông đạt được điều đó. Nếu Athành công, nhưng Bchạy và thất bại, nó sẽ thực thi C.

Lưu ý 1: nếu bạn bằng cách nào đó có thể đảm bảo Bluôn thành công và muốn gắn bó với một phiên bản ngắn, thì tôi vẫn chọn

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

kết thúc ( ... ), vì cái sau không cần thiết buộc một lớp con mới được tạo ra, có thể hoặc không thể được tối ưu hóa.

Lưu ý 2: cả hai hình thức giả định Akhông tạo ra đầu ra, điều này đúng trong ví dụ của bạn nhưng không nhất thiết phải như vậy nói chung. Điều đó có thể tránh được

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

Bạn có chắc chắn rằng { … }không buộc một lớp con được tạo ra do đường ống? Tôi quan sát các hành vi sau đây: pgrep bashpgrep bash | catif true; then pgrep bash; fi{ pgrep bash; }có một dòng đầu ra; ( pgrep bash; )( pgrep bash; ) | cat{ pgrep bash; } | catif true; then pgrep bash; fi | catcó hai dòng đầu ra.
wchargein

@wchargein ... | ...gây ra một lớp con được tạo ra, đó là điều không thể tránh khỏi. ( ... ), Ít nhất là về mặt lý thuyết, gây ra thêm subshell được tạo ra mà { ...; }tránh được, nhưng đó là những gì tôi muốn nói với "có thể hoặc không được tối ưu hóa đi": có thể là trong trường hợp đặc biệt này, vỏ nhận ra nó không quan trọng, các hiệu ứng sẽ như nhau.
hvd

5

Câu trả lời chính xác là đúng nhưng nó không bao gồm trường hợp sử dụng tiềm năng để không có đầu ra Alà đầu vào của D. Để đạt được điều đó, bạn sẽ cần chuyển hướng luồng Atùy theo nhu cầu của bạn.

  • Nếu bạn muốn loại bỏ đầu ra của Aanyway:

    { A >/dev/null && B || C; } | D
  • Nếu bạn muốn xem đầu ra của Athiết bị đầu cuối:

    { A >/dev/tty && B || C; } | D
  • Nếu bạn cần đầu ra Alà đầu vào của lệnh tiếp theo, Ebạn sẽ cần một nhóm lệnh bổ sung và chuyển hướng luồng:

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

Nếu tất cả điều này có vẻ quá phức tạp với bạn (như với tôi), tôi khuyên bạn nên sử dụng biến shell đặc biệt cho trạng thái thoát của Avà làm việc với điều đó:

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

Nếu bạn muốn ngắn gọn hơn nhưng không quá phức tạp, tôi đề nghị điều này:

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

(Xem thêm phần cuối của câu trả lời của hvd mà tôi không nhận thấy khi tôi viết câu trả lời ban đầu của mình.)


Câu trả lời của tôi không bao gồm điều đó. Xem những gì tôi đặt trong "Ghi chú 2:", nơi tôi chỉ cần di chuyển Ara khỏi đường ống.
hvd

@hvd: Bạn đã đúng và cảm ơn vì đã chỉ ra rằng một phần câu trả lời của bạn cho tôi! Tôi đã thay đổi yêu cầu của tôi và cung cấp cho bạn tín dụng phù hợp.
David Foerster
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.