Tại sao `sort <(ls -l)` hoạt động nhưng` sort <(ls -l) `không thành công?


32

Hôm nay tôi đang học một cái gì đó về fifo với bài viết này: Giới thiệu về Named Faucet , trong đó đề cập đến cat <(ls -l).

Tôi đã thực hiện một số thử nghiệm bằng cách sử dụng sort < (ls -l), phát hiện ra một lỗi:

-bash: syntax error near unexpected token `('`

Sau đó, tôi thấy tôi đã nhầm lẫn một không gian thừa trong lệnh.

Nhưng, tại sao lệnh bổ sung này sẽ dẫn đến thất bại này? Tại sao biểu tượng chuyển hướng phải gần với (?


Cần lưu ý rằng các vỏ * nix phân tách mọi thứ dựa trên khoảng trắng tạo ra các mã thông báo mà Alec đã đề cập.
gà con

Câu trả lời:


45

Bởi vì đó không phải là một <, nó <()hoàn toàn khác. Đây được gọi là sự thay thế quá trình , nó là một tính năng của một số shell nhất định cho phép bạn sử dụng đầu ra của một quá trình làm đầu vào cho một quá trình khác.

Các toán tử ><chuyển hướng đầu ra và đầu vào từ các tập tin . Các <()nhà điều hành giao dịch với các lệnh (quy trình), không phải tập tin. Khi bạn chạy

sort < (ls)

Bạn đang cố chạy lệnh lstrong một khung con (đó là ý nghĩa của dấu ngoặc đơn), sau đó chuyển giao lớp con đó dưới dạng tệp đầu vào sort. Điều này, tuy nhiên, không được chấp nhận cú pháp và bạn nhận được lỗi bạn đã thấy.


3
Câu trả lời của bạn là tốt, nhưng then sort is attempting to read the subshell as its input file→ điều này rõ ràng là sai, vì Bash thậm chí sẽ không phân tích cú pháp. Không lsphải cũng không sortthực sự chạy.
sleblanc

1
@sebleblanc điểm công bằng, đọc lại câu trả lời, cảm ơn.
terdon

1
Không có vỏ phụ trong trường hợp này. < (ls)không phải là mã thông báo hợp lệ ở đây.
cuonglm

@cuonglm không, vì bash coi nó là lỗi cú pháp. Quan điểm của tôi là (ls)sẽ chạy lstrong một subshell.
terdon

22

Bởi vì đó là cách nó có nghĩa là.

<(...)trong bashlà cú pháp để thay thế quá trình. Nó được sao chép từ cùng một toán tử trong ksh.

<, (, ), |, &, ;Là thẻ từ vựng đặc biệt trong bashđó được sử dụng để tạo thành nhà khai thác đặc biệt trong các kết hợp khác nhau. <, <(, <<, <&... mỗi người đều có vai trò của họ. <là để chuyển hướng. <file, < filesẽ chuyển hướng đầu vào từ một tập tin. <'(file)'sẽ chuyển hướng đầu vào từ một tệp được gọi (file), nhưng <(file)là một toán tử khác không phải là toán tử chuyển hướng.

< (file)sẽ được <theo sau (file). Trong bối cảnh đó, trong bash, (file)là không hợp lệ. (...)có thể hợp lệ dưới dạng một mã thông báo trong một số ngữ cảnh như:

(sub shell)
func () {
  ...
}
var=(foo bar)

Nhưng không phải trong

sort < (cmd)

Trong fishvỏ, nó khác. Trong fish, (...)là để thay thế lệnh (tương đương với $(...)trong bash). Và <là để chuyển hướng đầu vào như trong shell giống như Bourne.

Vì vậy, trong fish:

sort <(echo file)

sẽ giống như:

sort < (echo file)

Đó là:

sort < file

Nhưng đó là một cái gì đó hoàn toàn khác với bashquá trình thay thế.

Trong hệ yashvỏ, một vỏ POSIX khác, <(...)không phải để thay thế quy trình mà là để chuyển hướng quy trình

Trong đó,

sort <(ls -l)

Viết tắt của:

sort 0<(ls -l)

là một toán tử chuyển hướng. Nó ít nhiều tương đương với:

ls -l | sort

Trong khi ở bash, đường <(ls -l)được mở rộng thành đường ống, vì vậy nó giống như:

ls -l | sort /dev/fd/0

Trong zsh, (...)bị quá tải như một toán tử toàn cầu ( (*.txt|*.png)sẽ mở rộng đến txtpngcác tệp) và như là vòng loại toàn cầu ( *(/)ví dụ: mở rộng sang các tệp thư mục).

Trong zsh, trong:

sort < (ls -l)

Điều đó (ls -l)sẽ được coi là một vòng loại toàn cầu. Vòng lloại toàn cầu sẽ khớp với số lượng liên kết và mong đợi một số sau l(như trong ls -ld ./*(l2)danh sách các tệp có 2 liên kết), vì vậy đó là lý do tại sao bạn gặp zsh: number expectedlỗi ở đó.

sort < (w)zsh: no matches found: (w)thay vào đó sẽ đưa ra một lỗi thay vì (w)khớp với các tệp có tên trống có thể ghi.

sort < (w|cat)sẽ sắp xếp nội dung của các tập tin wvà / hoặc cattrong thư mục hiện tại ...


tại sao sort < $(ls -l)đưa ra lỗi này:bash: $(ls -l): ambiguous redirect
Edward Torvalds

@edwardtorvalds, vì $(ls -l)mở rộng ra nhiều hơn một từ. Sử dụng dấu ngoặc kép để ngăn chia + global ( sort < "$(echo file)"). Lưu ý rằng hành vi hoặc bashkhác với hành vi của POSIX sh trong bash đó sẽ phân chia + toàn cầu ở đó khi không tương tác (không phải khi được gọi như shvậy).
Stéphane Chazelas

bằng cách nhìn vào ls -l | sort /dev/fd/0tôi có thể nói rằng đầu ra của ls -lđược lưu trữ /dev/fd/0sortlệnh đọc nó để đưa ra đầu ra mong muốn. Tôi đang sử dụng tail -f --retry /dev/fd/0để theo dõi tập tin đó nhưng tôi không nhận được bất kỳ đầu ra nào. tại sao? Làm thế nào tôi có thể đọc tập tin đó?
Edward Torvalds

Trong cá, bạn có thể sử dụng (foo | psub)để đạt được sự thay thế quá trình đầu vào; không có sự thay thế (ha) để thay thế quá trình đầu ra.
Zanchey
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.