Đặt đường ống cho một lệnh đường ống duy nhất


18

Tôi cần phải thực thi một số lệnh shell được lấy từ tập lệnh không phải BASH (cụ thể là tập lệnh PHP) như sau:

command1 | command2 | command3

do đó, nếu command1thất bại với mã thoát khác không, thì mỗi lệnh khác cũng thất bại. Cho đến nay, những gì tôi nghĩ ra là:

set -o pipefail && command1 | command2 | command3

Nhưng ngay cả khi nó chạy tốt từ thiết bị đầu cuối, nó sẽ tạo ra điều này nếu được thực thi từ tập lệnh:

sh: 1: set: Tùy chọn bất hợp pháp -o pipefail


Có vẻ như /bin/shkhông thích set -o pipefail. Là nó thực sự bashngụy trang, hoặc nó là một vỏ khác nhau? Khi bashđược chạy như /bin/sh, nó có chấp nhận set -o pipefail?
Jonathan Leffler

@JonathanLeffler Khi tôi chạy /bin/sh set -o pipefailnó nói /bin/sh: 0: Can't open set(điều tương tự với sudo). Hy vọng tôi đã thử nó đúng. Hệ thống là Ubuntu 12.
Desmond Hume

Bạn cần phải thử /bin/sh -c "set -o pipefail"; vì vậy, shell đã cố gắng thực thi một tập lệnh trong thư mục hiện tại được gọi setvà nó không tìm thấy nó.
Jonathan Leffler

@JonathanLeffler /bin/sh -c "set -o pipefail"không hoạt động, tuy nhiên, bash -c "set -o pipefail"không.
Desmond Hume

Vì vậy, vấn đề của bạn là tập lệnh được chạy /bin/shmà không nhận ra set -o pipefail. Do đó, bạn sẽ cần đảm bảo rằng tập lệnh được chạy /bin/bashthay vì /bin/sh. Hoặc, nếu bạn tự tin, dũng cảm - và có thể là điên rồ - hãy thay đổi /bin/shthành một liên kết đến hoặc sao chép, /bin/bashthay vì bất kỳ vỏ nào hiện tại được liên kết hoặc một bản sao. Nếu bạn chắc chắn đó /bin/shbash, thì bạn đang sử dụng hành vi bashkhông phơi bày khi chạy như /bin/sh; sử dụng bashnhư bash.
Jonathan Leffler

Câu trả lời:


18

Từ dòng lệnh Bash, bạn sẽ cần phải gọi một mạng con để tránh pipefailbị đặt sau đó:

$ (set -o pipefail && command1 | command2 | command3)

Điều này sẽ hạn chế ảnh hưởng của pipefailtùy chọn đối với lớp con được tạo bởi dấu ngoặc đơn (...).

Một ví dụ thực tế:

$ (set -o pipefail && false | true) && echo pipefail inactive || echo pipefail active
pipefail active

Nếu bạn sử dụng một cuộc gọi shell rõ ràng với -ctùy chọn bạn không cần một mạng con, có thể có bashhoặc có shbí danh để bash:

$ bash -c "set -o pipefail && false | true" && echo pipefail inactive || echo pipefail active
pipefail active
$ sh -c "set -o pipefail && false | true" && echo pipefail inactive || echo pipefail active
pipefail active

Vì bạn shkhông chấp nhận pipefailtùy chọn, tôi sẽ phải thừa nhận rằng đó là một phiên bản cũ hơn hoặc đã được sửa đổi bash- hoặc thực tế nó hoàn toàn là một vỏ khác.


1
Có phải $trong phần đầu tiên, một phần của lệnh chỉ là một dấu nhắc shell? Đã thử cả hai cách, không thực sự làm việc. Các bash -ccách luôn luôn làm việc, không quá tao nhã tho ..
Desmond Hume

5

Không chắc chắn tại sao nó không được đề cập ở trên, nhưng có thể rõ ràng là không đặt pipefail, sử dụng set +o pipefail.

set -o pipefail
command1 | command2 | command3
set +o pipefail

Nếu bạn đang thực thi một đoạn và không chắc chắn về tập pipefailđã được đặt, bạn có thể sử dụng phần này với phần con như đề xuất trước đây:

# explicitly execute with pipefail set
(set -o pipefail ; command1 | command2 | command3 )
# explicitly execute with pipefail unset
(set +o pipefail ; command1 | command2 | command3 )

0

Bạn có thể sử dụng $ (lệnh1) kết hợp với $? :

a=$(echo "a")
[ $? -eq 0 ] && b=$(echo $a"b")
[ $? -eq 0 ] && c=$(echo $b"c")
echo $c

In "abc"

a=$(ls unexitingDir)
[ $? -eq 0 ] && b=$(echo $a"b")
[ $? -eq 0 ] && c=$(echo $b"c")
echo $c

In "".

"[$? -Eq 0] &&" có nghĩa là lệnh sau chỉ được thực thi nếu lệnh trước bị hủy.

Điều đó không trả lời câu hỏi của bạn nhưng đó là một giải pháp cho vấn đề của bạn.


Có nghĩa là tôi sẽ luôn cần lưu trữ đầu ra của mỗi lệnh vào một biến?
Desmond Hume

Luôn luôn tôi không biết nhưng với giải pháp của tôi, bạn sẽ có (nếu bạn cần nó cho lệnh tiếp theo của bạn). Trừ khi bạn chỉ có thể viếtcommand1 && command2 && command3
cglacet
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.