$(<file)
(cũng hoạt động với `<file`
) là một toán tử đặc biệt của vỏ Korn được sao chép bởi zsh
và bash
. Nó trông rất giống như thay thế lệnh nhưng nó không thực sự.
Trong shell POSIX, một lệnh đơn giản là:
< file var1=value1 > file2 cmd 2> file3 args 3> file4
Tất cả các phần là tùy chọn, bạn chỉ có thể có chuyển hướng, chỉ lệnh, chỉ gán hoặc kết hợp.
Nếu có các chuyển hướng nhưng không có lệnh, các chuyển hướng được thực hiện (vì vậy a > file
sẽ mở và cắt ngắn file
), nhưng sau đó không có gì xảy ra. Vì thế
< file
Mở file
để đọc, nhưng sau đó không có gì xảy ra vì không có lệnh. Vì vậy, file
sau đó được đóng lại và đó là nó. Nếu $(< file)
là một thay thế lệnh đơn giản , thì nó sẽ mở rộng thành không có gì.
Trong đặc tả POSIX , trong $(script)
, nếu script
chỉ bao gồm các chuyển hướng, sẽ tạo ra kết quả không xác định . Đó là cho phép hành vi đặc biệt của vỏ Korn.
Trong ksh (ở đây đã được thử nghiệm ksh93u+
), nếu tập lệnh bao gồm một và chỉ một lệnh đơn giản (mặc dù các bình luận được cho phép trước và sau) chỉ bao gồm các chuyển hướng (không có lệnh, không có chuyển nhượng) và nếu chuyển hướng đầu tiên là stdin (fd 0) chỉ chuyển hướng ( <
, <<
hoặc <<<
) chuyển hướng, vì vậy:
$(< file)
$(0< file)
$(<&3)
(cũng $(0>&3)
thực sự là điều đó có hiệu lực cùng một nhà điều hành)
$(< file > foo 2> $(whatever))
nhưng không:
$(> foo < file)
- cũng không
$(0<> file)
- cũng không
$(< file; sleep 1)
- cũng không
$(< file; < file2)
sau đó
- tất cả trừ chuyển hướng đầu tiên đều bị bỏ qua (chúng được phân tích cú pháp)
- và nó mở rộng đến nội dung của tệp / heredoc / herestring (hoặc bất cứ điều gì có thể được đọc từ bộ mô tả tệp nếu sử dụng những thứ như
<&3
) trừ các ký tự dòng mới.
như thể sử dụng $(cat < file)
ngoại trừ đó
- việc đọc được thực hiện bên trong bởi vỏ chứ không phải bởi
cat
- không có đường ống cũng không có quá trình bổ sung
- như một hệ quả của điều trên, vì mã bên trong không được chạy trong một lớp con, nên mọi sửa đổi vẫn còn sau đó (như trong
$(<${file=foo.txt})
hoặc $(<file$((++n)))
)
- đọc lỗi (mặc dù không phải lỗi trong khi mở tệp hoặc sao chép mô tả tệp) bị bỏ qua trong âm thầm.
Trong zsh
, nó giống ngoại trừ rằng hành vi đặc biệt chỉ được kích hoạt khi chỉ có một tập tin chuyển hướng đầu vào ( <file
hoặc 0< file
, không <&3
, <<<here
, < a < b
...)
Tuy nhiên, ngoại trừ khi mô phỏng các vỏ khác, trong:
< file
<&3
<<< here...
đó là khi chỉ có các chuyển hướng đầu vào mà không có lệnh, bên ngoài thay thế lệnh, zsh
chạy $READNULLCMD
(máy nhắn tin theo mặc định) và khi có cả chuyển hướng đầu vào và đầu ra, $NULLCMD
( cat
theo mặc định), do đó ngay cả khi $(<&3)
không được nhận dạng là đặc biệt Toán tử, nó vẫn sẽ hoạt động như ksh
mặc dù bằng cách gọi một máy nhắn tin để làm điều đó (máy nhắn tin đó hoạt động như thế cat
vì thiết bị xuất chuẩn của nó sẽ là một đường ống).
Tuy nhiên, trong khi ksh
, $(< a < b)
sẽ mở rộng sang nội dung của a
, trong zsh
đó, nó sẽ mở rộng sang nội dung của a
và b
(hoặc chỉ b
khi multios
tùy chọn bị tắt), $(< a > b)
sẽ sao chép a
vào b
và mở rộng thành không có gì, v.v.
bash
có một toán tử tương tự nhưng với một vài khác biệt:
ý kiến được cho phép trước nhưng không sau:
echo "$(
# getting the content of file
< file)"
hoạt động nhưng:
echo "$(< file
# getting the content of file
)"
mở rộng ra không có gì.
giống như trong zsh
, chỉ có một tệp chuyển hướng stdin, mặc dù không có quay lại a $READNULLCMD
, vì vậy $(<&3)
, $(< a < b)
thực hiện chuyển hướng nhưng mở rộng thành không có gì.
- vì một số lý do, trong khi
bash
không gọi cat
, nó vẫn tạo ra một quy trình cung cấp nội dung của tệp thông qua một đường ống làm cho nó tối ưu hóa hơn nhiều so với các trình bao khác. Nó có hiệu lực giống như một $(cat < file)
nơi cat
sẽ là một căn hộ cat
.
- do hậu quả của những điều trên, bất kỳ thay đổi nào được thực hiện bên trong đều bị mất sau đó (
$(<${file=foo.txt})
ví dụ, trong phần được đề cập ở trên, $file
nhiệm vụ đó sẽ bị mất sau đó).
Trong bash
, IFS= read -rd '' var < file
(cũng hoạt động trong zsh
) là một cách hiệu quả hơn để đọc nội dung của tệp văn bản thành một biến. Nó cũng có lợi ích của việc bảo tồn các ký tự dòng mới. Xem thêm $mapfile[file]
trong zsh
(trong zsh/mapfile
mô-đun và chỉ cho các tệp thông thường) cũng hoạt động với các tệp nhị phân.
Lưu ý rằng các biến thể dựa trên pdksh ksh
có một vài biến thể so với ksh93. Quan tâm, trong mksh
(một trong những vỏ có nguồn gốc pdksh), trong
var=$(<<'EOF'
That's multi-line
test with *all* sorts of "special"
characters
EOF
)
được tối ưu hóa ở chỗ nội dung của tài liệu ở đây (không có các ký tự dấu) được mở rộng mà không sử dụng tệp tạm thời hoặc đường ống như trường hợp của các tài liệu ở đây, làm cho nó trở thành một cú pháp trích dẫn nhiều dòng hiệu quả.
Để có thể di động cho tất cả các phiên bản của ksh
, zsh
và bash
, tốt nhất là giới hạn chỉ $(<file)
tránh các bình luận và lưu ý rằng việc sửa đổi các biến được thực hiện trong phạm vi có thể hoặc không được bảo tồn.
bash
sẽ diễn giải điều đó nhưcat filename
", bạn có nghĩa là hành vi này là cụ thể để thay thế lệnh? Bởi vì nếu tôi tự chạy< filename
, bash sẽ không biến mất. Nó sẽ không xuất ra gì và đưa tôi trở lại dấu nhắc.