Bash: thay thế quá trình và stdin


13

Dòng sau đây là rõ ràng:

echo "bla" | foo | bar

Nhưng những người dưới đây có làm như vậy không?

echo "bla" | bar <(foo)
echo "bla" | bar < <(foo)

foobarđọc "bla" từ stdin và tại sao?

Ý tôi là, tất nhiên, tôi chỉ có thể viết mã và kiểm tra nó, nhưng tôi không chắc đó là hành vi được xác định hay tôi đang khai thác các tính năng mà tôi không nên dựa vào.

Câu trả lời:


9

Đó là phụ thuộc vỏ và không được ghi lại AFAICS. Trong kshbash, trong trường hợp đầu tiên, foosẽ chia sẻ cùng một stdin như bar. Họ sẽ chiến đấu cho đầu ra của echo.

Vì vậy, ví dụ trong,

$ seq 10000 | paste - <(tr 1 X)'
1       X
2       X042
3       X043
4       X044
5       X045
[...]

Bạn thấy bằng chứng pasteđọc mọi khối văn bản khác từ seqđầu ra trong khi trđọc các khối khác.

Với zsh, nó nhận được stdin bên ngoài (trừ khi nó là một thiết bị đầu cuối và vỏ không tương tác trong trường hợp nó được chuyển hướng từ /dev/null). ksh(nơi nó bắt nguồn) zshbashlà những chiếc vỏ giống như Bourne duy nhất có hỗ trợ thay thế quy trình AFAIK.

Trong echo "bla" | bar < <(foo), lưu ý rằng barstdin sẽ là đường ống được cung cấp bởi đầu ra của foo. Đó là hành vi được xác định rõ. Trong trường hợp đó, có vẻ như foostdin là đường ống được cung cấp bởi echotất cả ksh, zshbash.

Nếu bạn muốn có một hành vi nhất quán trên cả ba vỏ và là bằng chứng trong tương lai vì hành vi có thể thay đổi vì nó không được ghi lại, tôi sẽ viết nó:

echo bla | { bar <(foo); }

Để chắc chắn rằng foostdin cũng là đường ống từ echo(Tôi không thể hiểu tại sao bạn muốn làm điều đó). Hoặc là:

echo bla | bar <(foo < /dev/null)

Để đảm bảo fookhông không đọc từ các đường ống từ echo. Hoặc là:

{ echo bla | bar 3<&- <(foo <&3); } 3<&0

Để có foostdin của stdin bên ngoài như trong các phiên bản hiện tại của zsh.


"Trong trường hợp đó, stdin của foo là đường ống được cung cấp bởi tiếng vang trong tất cả các ksh, zsh và bash." Bạn đã thử nghiệm điều này bằng tay ngay bây giờ, hoặc nó ở đâu đó được ghi lại?
etam1024

Liệu "trong trường hợp đầu tiên" trong dòng đầu tiên có đề cập đến `| foo | thanh` hoặc `| thanh <(foo) `?
Volker Siegel

4

echo "bla" | foo | bar: Đầu ra của echo "bla"được chuyển hướng đến foo, có đầu ra được chuyển hướng đến bar.

echo "bla" | bar <(foo): Đó là một ống đầu ra của echo "bla"để bar. Nhưng barđược thực hiện với một đối số. Đối số là đường dẫn đến trình giải mã tệp, nơi đầu ra của foosẽ được gửi đến. Đối số này hoạt động giống như một tệp chứa đầu ra của foo. Vì vậy, điều đó không giống nhau.

echo "bla" | bar < <(foo): Người ta có thể cho rằng đầu ra của echo "bla"nên được gửi đến barvà toàn bộ câu lệnh tương đương với câu lệnh đầu tiên. Nhưng, điều đó không đúng. Điều sau đây xảy ra: Bởi vì chuyển hướng đầu vào <được thực hiện sau đường ống ( |), nó ghi đè lên nó . Vì vậy, echo "bla"không được dẫn đến thanh. Thay vào đó, đầu ra của foođược chuyển hướng làm đầu vào tiêu chuẩn bar. Để xóa điều này, hãy xem lệnh và đầu ra sau đây:

$ echo "bla" | cat < <(echo "foo")
foo

Như bạn thấy echo "bla"là thay thế bởi echo "foo".

Bây giờ hãy xem lệnh này:

$ echo "bar" | cat < <(awk '{printf "%s and foo", $0}')
bar and foo

Vì vậy, echo "bar"được dẫn đến awk, đọc stdin và thêm chuỗi and foovào đầu ra. Đầu ra này được dẫn đến cat.


Và câu hỏi của tôi là: "Có phải thực tế là awkđọc" thanh "là một hành vi xác định?"
etam1024

Vâng, đúng vậy. cmd1 < <(cmd2)cư xử giống như cmd2 | cmd1.
hỗn loạn

Hoặc cmd1 | cmd2 | cmd3giống nhưcmd1 | cmd3 < <(cmd2)
hỗn loạn

3
Nếu đó là wikipedia tôi sẽ đặt thẻ "cần dẫn nguồn" vào các câu của bạn :) Toàn bộ câu hỏi của tôi là nó hoạt động như bạn nói, nhưng tôi không thể tìm thấy bất kỳ tài liệu nào về nó.
etam1024
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.