Sử dụng các công cụ riêng của hộp thoại: cờ --output-fd
Nếu bạn đọc trang man cho hộp thoại, có tùy chọn --output-fd
, cho phép bạn đặt rõ ràng nơi đầu ra đi (STDOUT 1, STDERR 2), thay vì theo mặc định sẽ chuyển sang STDERR.
Dưới đây bạn có thể thấy tôi đang chạy dialog
lệnh mẫu , với tuyên bố rõ ràng rằng đầu ra phải đi đến mô tả tệp 1, cho phép tôi lưu nó vào MYVAR.
MYVAR=$(dialog --inputbox "THIS OUTPUT GOES TO FD 1" 25 25 --output-fd 1)
Sử dụng ống có tên
Phương pháp thay thế có nhiều tiềm năng tiềm ẩn, là sử dụng một cái gì đó được gọi là ống dẫn .
#!/bin/bash
mkfifo /tmp/namedPipe1 # this creates named pipe, aka fifo
# to make sure the shell doesn't hang, we run redirection
# in background, because fifo waits for output to come out
dialog --inputbox "This is an input box with named pipe" 40 40 2> /tmp/namedPipe1 &
# release contents of pipe
OUTPUT="$( cat /tmp/namedPipe1 )"
echo "This is the output " $OUTPUT
# clean up
rm /tmp/namedPipe1
Tổng quan sâu hơn về câu trả lời của user.dz với cách tiếp cận thay thế
Câu trả lời ban đầu của user.dz và ByteCommander giải thích rằng cả hai đều cung cấp một giải pháp tốt và tổng quan về những gì nó làm. Tuy nhiên, tôi tin rằng một phân tích sâu hơn có thể có lợi để giải thích tại sao nó hoạt động.
Trước hết, điều quan trọng là phải hiểu hai điều: vấn đề chúng ta đang cố gắng giải quyết là gì và hoạt động cơ bản của các cơ chế vỏ mà chúng ta đang giải quyết là gì. Nhiệm vụ là bắt đầu ra của lệnh thông qua thay thế lệnh. Theo tổng quan đơn giản mà mọi người đều biết, các lệnh thay thế nắm bắt stdout
lệnh và để nó được sử dụng lại bởi một thứ khác. Trong trường hợp này, result=$(...)
phần nên lưu đầu ra của bất kỳ lệnh nào được chỉ định bởi ...
một biến được gọi result
.
Bên dưới mui xe, việc thay thế lệnh thực sự được thực hiện dưới dạng đường ống, trong đó có một tiến trình con (lệnh thực tế chạy) và quá trình đọc (giúp lưu đầu ra vào biến). Điều này là hiển nhiên với một dấu vết đơn giản của các cuộc gọi hệ thống. Lưu ý rằng mô tả tập tin 3 là đầu đọc của ống, trong khi 4 là đầu ghi. Đối với tiến trình con của echo
, ghi vào stdout
bộ mô tả tệp 1, bộ mô tả tệp đó thực sự là bản sao của bộ mô tả tệp 4, là đầu ghi của đường ống. Lưu ý rằng stderr
không đóng vai trò ở đây, đơn giản vì đó chỉ là một đường ống kết nối stdout
.
$ strace -f -e pipe,dup2,write,read bash -c 'v=$(echo "X")'
...
pipe([3, 4]) = 0
strace: Process 6200 attached
[pid 6199] read(3, <unfinished ...>
[pid 6200] dup2(4, 1) = 1
[pid 6200] write(1, "X\n", 2 <unfinished ...>
[pid 6199] <... read resumed> "X\n", 128) = 2
[pid 6200] <... write resumed> ) = 2
[pid 6199] read(3, "", 128) = 0
[pid 6200] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=6200, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
+++ exited with 0 +++
Chúng ta hãy quay lại câu trả lời ban đầu trong một giây. Vì bây giờ chúng ta biết rằng dialog
viết hộp TUI stdout
, trả lời stderr
và trong khi thay thế lệnh stdout
được chuyển sang một nơi khác, chúng ta đã có một phần của giải pháp - chúng ta cần phải viết lại các mô tả tệp theo cách đó stderr
sẽ được chuyển đến quy trình đọc. Đây là 2>&1
một phần của câu trả lời. Tuy nhiên, chúng ta làm gì với hộp TUI?
Đó là nơi mô tả tệp 3 xuất hiện. Tòa nhà dup2()
cho phép chúng tôi sao chép mô tả tệp, làm cho chúng tham chiếu hiệu quả đến cùng một vị trí, nhưng chúng tôi có thể thao tác chúng một cách riêng biệt. Mô tả tập tin của các quá trình có thiết bị đầu cuối điều khiển gắn thực sự trỏ đến thiết bị đầu cuối cụ thể. Điều này là hiển nhiên nếu bạn làm
$ ls -l /proc/self/fd
total 0
lrwx------ 1 user1 user1 64 Aug 20 10:30 0 -> /dev/pts/5
lrwx------ 1 user1 user1 64 Aug 20 10:30 1 -> /dev/pts/5
lrwx------ 1 user1 user1 64 Aug 20 10:30 2 -> /dev/pts/5
lr-x------ 1 user1 user1 64 Aug 20 10:30 3 -> /proc/6424/fd
/dev/pts/5
thiết bị đầu cuối giả hiện tại của tôi ở đâu . Do đó, nếu bằng cách nào đó chúng ta có thể lưu điểm đến này, chúng ta vẫn có thể ghi hộp TUI lên màn hình thiết bị đầu cuối. Đó là những gì exec 3>&1
. command > /dev/null
Ví dụ, khi bạn gọi một lệnh với chuyển hướng , shell sẽ chuyển qua bộ mô tả tệp stdout của nó và sau đó sử dụng dup2()
để ghi bộ mô tả tệp đó vào /dev/null
. Các exec
lệnh Thực hiện một cái gì đó tương tự nhưdup2()
mô tả file cho phiên toàn vỏ, do đó làm cho bất kỳ lệnh kế thừa mô tả tập tin đã chuyển hướng. Tương tự với exec 3>&1
. Bộ mô tả tệp 3
bây giờ sẽ tham chiếu / trỏ đến thiết bị đầu cuối kiểm soát và bất kỳ lệnh nào chạy trong phiên shell đó sẽ biết về nó.
Vì vậy, khi result=$(dialog --inputbox test 0 0 2>&1 1>&3);
xảy ra, shell tạo một ống để hộp thoại để ghi, nhưng 2>&1
trước tiên cũng sẽ làm cho bộ mô tả tệp của lệnh 2 được sao chép vào bộ mô tả tệp ghi của ống đó (do đó làm cho đầu ra đi đến đầu đọc của ống và vào biến) , trong khi bộ mô tả tệp 1 sẽ được sao chép lên 3. Điều này sẽ làm cho bộ mô tả tệp 1 vẫn tham chiếu đến thiết bị đầu cuối kiểm soát và hộp thoại TUI sẽ hiển thị trên màn hình.
Bây giờ, thực sự có một tay ngắn cho thiết bị đầu cuối kiểm soát hiện tại của quá trình, đó là /dev/tty
. Do đó, giải pháp có thể được đơn giản hóa mà không cần sử dụng các mô tả tệp, chỉ cần vào:
result=$(dialog --inputbox test 0 0 2>&1 1>/dev/tty);
echo "$result"
Những điều quan trọng cần nhớ:
- mô tả tập tin được kế thừa từ shell bởi mỗi lệnh
- thay thế lệnh được thực hiện như đường ống
- bộ mô tả tệp trùng lặp sẽ tham chiếu đến cùng một nơi với bản gốc, nhưng chúng ta có thể thao tác riêng từng bộ mô tả tệp
Xem thêm
mktemp
lệnh để tạo một tệp tạm thời.