Có cách nào để viết lại cấu trúc lệnh A && B || C | D
sao 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ụ:
Có cách nào để viết lại cấu trúc lệnh A && B || C | D
sao 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ụ:
Câu trả lời:
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 || C
sẽ được dẫn vào D
.
sh
:)
A
là bên trong lớp vỏ, điều này cũng bao gồm A
.)
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 B
hoặc C
, nhưng A && B || C
không đạt được điều đó. Nếu A
thành công, nhưng B
chạ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 B
luô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 A
khô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
{ … }
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 bash
và pgrep bash | cat
và if true; then pgrep bash; fi
và { pgrep bash; }
có một dòng đầu ra; ( pgrep bash; )
và ( pgrep bash; ) | cat
và { pgrep bash; } | cat
và if true; then pgrep bash; fi | cat
có hai dòng đầu ra.
... | ...
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.
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 A
là đầu vào của D
. Để đạt được điều đó, bạn sẽ cần chuyển hướng luồng A
tùy theo nhu cầu của bạn.
Nếu bạn muốn loại bỏ đầu ra của A
anyway:
{ A >/dev/null && B || C; } | D
Nếu bạn muốn xem đầu ra của A
thiết bị đầu cuối:
{ A >/dev/tty && B || C; } | D
Nếu bạn cần đầu ra A
là đầu vào của lệnh tiếp theo, E
bạ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 A
và 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.)
A
ra khỏi đường ống.
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