Tôi có thể chỉ định đầu vào được chuyển hướng trước lệnh ghép không?


8

Bash cho phép bạn chỉ định một đầu vào được chuyển hướng trước một lệnh:

$ <lines sed 's/^/line: /g'
line: foo
line: bar

Bash cũng cho phép bạn chuyển hướng đầu vào thành một lệnh ghép như một whilevòng lặp:

$ while read line; do echo "line: $line"; done <lines
line: foo
line: bar

Tuy nhiên, khi tôi cố gắng chỉ định đầu vào được chuyển hướng trước một whilevòng lặp, tôi gặp lỗi cú pháp:

$ <lines while read line; do echo "line: $line"; done
bash: syntax error near unexpected token `do'

Có chuyện gì với cái này vậy? Có phải là không thể chỉ định đầu vào được chuyển hướng trước một lệnh ghép trong Bash? Nếu vậy, tại sao không?


(Tôi đặc biệt muốn biết vì tôi đang hướng đầu ra của lệnh đến một vòng lặp while trong bối cảnh shell hiện tại thông qua thay thế quy trình và tôi thích nó hơn nếu phần đầu của mã không phải xuất hiện sau phần thứ hai .)
Stuart P. Bentley

Câu trả lời:



6

Bạn có thể zsh, không phải trong bashchoroba đã chỉ cho bạn tài liệu , nhưng nếu bạn muốn chuyển hướng trước đó, bạn có thể làm những việc như:

< file eval '
  while IFS= read -r line; do
    ...
  done'

Hoặc (trên các hệ thống có hỗ trợ /dev/fd/n):

< file 3<< 'EOF' . /dev/fd/3
while IFS= read -r line; do
  ...
done
EOF

(không phải là bạn muốn làm điều đó).

Bạn cũng có thể làm:

exec 3< file
while IFS= read -r line <&3; do
  ...
done
exec 3<&-

(lưu ý rằng execsẽ thoát khỏi tập lệnh nếu filekhông thể mở).

Hoặc sử dụng một chức năng:

process()
  while IFS= read -r line; do
    ...
  done

< file process

Tự hỏi nếu eval/dev/fd/các tuyến đường đều nhanh như nhau.
Deer Hunter

1
@DeerHunter, << EOFliên quan đến việc tạo một tệp tạm thời, nộp nó lên và sau đó mở nó, đọc nó và giải thích khi bạn đọc nó. Nó chắc chắn sẽ nhanh hơn, mặc dù có lẽ không đáng chú ý vì dù sao nó cũng sẽ xảy ra trong bộ nhớ.
Stéphane Chazelas

"Sử dụng một hàm" không thực sự hữu ích - Tôi vẫn phải viết hàm trước khi mã được hướng vào nó (mặc dù tôi cho rằng tôi có thể viết một hàm cho điều đó, với hai hàm theo thứ tự).
Stuart P. Bentley

command execcó thể xử lý vấn đề thoát như w / nội dung khác. nhưng nó trở nên quá muộn để xử lý các bit từ dành riêng.
mikeerv

@ StéphaneChazelas Lý do sử dụng tệp tạm thời thay vì đường ống là gì?
kasperd

3

Bạn có thể sử dụng thay thế đó, nếu bạn muốn đi trước đầu vào:

cat lines | while read line; do echo "line: $line"; done

Tôi cần điều này được thực thi trong bối cảnh shell hiện tại - không có đường ống. (Mã trong câu hỏi chỉ là một ví dụ đơn giản.)
Stuart P. Bentley

2

Bạn có thể sử dụng exec để chuyển hướng stdin.

Trong một kịch bản:

exec < <(cat lines)
while read line ; do echo "line: $line"; done

Bạn không thể sử dụng trong shell đăng nhập (nó sẽ kết xuất tệp trên thiết bị xuất chuẩn và thoát). Trong trường hợp đó, bạn có thể mở một mô tả tệp khác:

exec 3< <(cat lines)
while read -u 3 line ; do echo "line: $line"; done

Để tham khảo: Sử dụng exec


Và nếu tôi đang sử dụng stdin cho một thứ khác, tôi sẽ bao quanh mã exec 3<&0exec <&3phải không? (đó hoặc sử dụng & 3 cho chuyển hướng tức là ví dụ thứ hai của bạn)
Stuart P. Bentley

Có, bạn "lưu" stdin hiện tại vào một bộ mô tả tệp khác và khi bạn hoàn thành, bạn có thể khôi phục nó. (nó được giải thích rõ trong ví dụ đầu tiên trong tài liệu được liên kết)
nhện
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.