Vấn đề cơ bản mà bạn cần phải giải quyết là làm thế nào để có được cả hai việc thực hiện time
và chuyển nhượng biến xảy ra trong cùng một trình bao, mà không có tệp tạm thời. Hầu như mọi phương thức Bash đều cung cấp đường ống đầu ra của một thứ đến một thứ khác, hoặc bắt đầu ra của một lệnh, có một mặt làm việc trong một vỏ con.
Dưới đây là một cách để bạn có thể làm điều đó mà không có một tập tin tạm thời, nhưng tôi sẽ cảnh báo bạn, nó không đẹp, nó không phải là cầm tay để tiện ích khác, và nó đòi hỏi ít nhất Bash 4:
coproc co { cat; }; times 1>&${co[1]}; eval "exec ${co[1]}>&-"; mapfile -tu ${co[0]} times_a
Tôi sẽ giải thích điều này cho bạn:
coproc co { cat; }
Điều này tạo ra một coprocess; một quy trình chạy ở chế độ nền, nhưng bạn được cung cấp đường ống để nói với đầu vào tiêu chuẩn và đầu ra tiêu chuẩn, là số FD ${co[0]}
(tiêu chuẩn trong số cat
) và ${co[1]}
(tiêu chuẩn trong số cat
). Các lệnh được thực hiện trong một subshell, vì vậy chúng ta không thể thực hiện một trong các mục tiêu của chúng ta (chạy times
hoặc đọc vào một biến), nhưng chúng ta có thể sử dụng cat
để truyền đầu vào thông qua đầu ra, và sau đó sử dụng đường ống đó để nói chuyện với times
và mapfile
trong trình bao hiện tại.
times >&${co[1]};
Run times
, chuyển hướng tiêu chuẩn của nó ra tiêu chuẩn trong các lệnh cat
.
eval "exec ${co[1]}>&-"
Đóng đầu vào của lệnh cat
. Nếu chúng tôi không làm điều này, cat
sẽ tiếp tục chờ đầu vào, giữ đầu ra của nó mở và mapfile
sẽ tiếp tục chờ đợi điều đó, làm cho hệ vỏ của bạn bị treo. exec
, khi không có lệnh nào, chỉ cần áp dụng các chuyển hướng của nó đến trình bao hiện tại; chuyển hướng đến -
đóng một FD. Chúng ta cần sử dụng eval
vì Bash có vẻ gặp rắc rối với exec ${co[1]}>&-
, giải thích FD làm lệnh thay vì một phần của chuyển hướng; sử dụng eval
cho phép biến đó được thay thế đầu tiên, và sau đó được thực thi.
mapfile -tu ${co[0]} times_a
Cuối cùng, chúng tôi thực sự đọc dữ liệu từ tiêu chuẩn ra khỏi coprocess. Chúng tôi đã quản lý cả hai lệnh times
và lệnh mapfile
trong trình bao này và không sử dụng tệp tạm thời, mặc dù chúng tôi đã sử dụng quy trình tạm thời làm đường dẫn giữa hai lệnh.
Lưu ý rằng điều này có một cuộc đua tinh tế. Nếu bạn thực hiện các lệnh này một, thay vì tất cả là một lệnh, lệnh cuối cùng không thành công; bởi vì khi bạn đóng tiêu chuẩn cat
s, nó sẽ thoát ra, khiến cho coprocess thoát ra và FD bị đóng. Dường như khi được thực hiện trên cùng một dòng, mapfile
được thực hiện đủ nhanh để coprocess vẫn mở khi nó chạy, và do đó nó có thể đọc từ đường ống; nhưng tôi có thể may mắn. Tôi đã không tìm ra một cách tốt đẹp xung quanh này.
Tất cả đã nói, nó đơn giản hơn nhiều chỉ để viết ra tệp tạm thời. Tôi sẽ sử dụng mktemp
để tạo ra một tên tập tin, và nếu bạn đang ở trong một kịch bản, thêm một cái bẫy để đảm bảo rằng bạn dọn dẹp tempfile của bạn trước khi thoát:
tempnam=$(mktemp)
trap "rm '$tempnam'" EXIT
times > ${tempnam}
mapfile -t times_a < ${tempnam}
Tôi ước gì có thể upvote này thậm chí nhiều hơn, tôi đã học được rất nhiều đọc này, câu trả lời thực sự tốt đẹp! – higuaro