대화 상자 자체 도구 사용 : --output-fd 플래그
대화 상자에 대한 매뉴얼 페이지를 읽는 경우 --output-fd
기본적으로 STDERR로 이동하는 대신 출력이 진행되는 위치 (STDOUT 1, STDERR 2)를 명시 적으로 설정할 수있는 옵션 이 있습니다.
아래 dialog
에서 출력이 파일 설명자 1로 이동하여 MYVAR에 저장할 수 있음을 명시 적으로 지정하여 sample command 실행 중을 볼 수 있습니다 .
MYVAR=$(dialog --inputbox "THIS OUTPUT GOES TO FD 1" 25 25 --output-fd 1)
명명 된 파이프 사용
숨겨진 잠재력이 많은 대안은 named pipe라는 것을 사용하는 것 입니다.
#!/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
대체 접근 방식 을 사용하는 user.dz의 답변에 대한 심층적 개요
user.dz의 원래 답변과 ByteCommander의 설명 은 좋은 해결책과 그 기능에 대한 개요를 제공합니다. 그러나 더 깊은 분석이 왜 효과가 있는지 설명하는 데 도움이 될 수 있다고 생각 합니다.
우선, 우리가 해결하려는 문제는 무엇이며 우리가 다루고있는 쉘 메커니즘의 기본 작동은 무엇인지 이해하는 것이 중요합니다. 이 작업은 명령 대체를 통해 명령의 출력을 캡처하는 것입니다. 모든 사람이 알고있는 단순한 개요에서 명령 대체 stdout
는 명령의 명령을 캡처하여 다른 것으로 재사용 할 수있게합니다. 이 경우 result=$(...)
부품은 지정된 모든 명령의 출력을 ...
이라는 변수에 저장해야합니다 result
.
후드 아래에서 명령 대체는 실제로 파이프로 구현되며, 하위 프로세스 (실행되는 실제 명령)와 읽기 프로세스 (출력을 변수에 저장)가 있습니다. 이것은 간단한 시스템 호출 추적으로 분명합니다. 파일 설명자 3은 파이프의 읽기 끝이고 4는 쓰기 끝입니다. 파일 디스크립터 1에 echo
쓰는 하위 프로세스의 경우 stdout
해당 파일 디스크립터는 실제로 파일 디스크립터 4의 사본이며 파이프의 쓰기 엔드입니다. 공지 사항 stderr
은 연결 파이프의 간단하기 때문에, 여기에 역할이 재생되지 않는 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 +++
잠시 원래 답변으로 돌아가 봅시다. 이제 우리 dialog
는 TUI 상자에을 쓰고 stdout
, 대답하고 stderr
, 명령 대체 stdout
가 다른 곳으로 파이프 된다는 것을 알고 있으므로 이미 솔루션의 일부를 가지고 stderr
있습니다. 독자 프로세스에 파이프 될 방식으로 파일 설명자를 다시 연결해야합니다. 이것이 2>&1
답 의 일부입니다. 그러나 TUI box로 무엇을합니까?
파일 디스크립터 3이 들어온 곳입니다. dup2()
syscall을 사용하면 파일 디스크립터를 복제하여 동일한 위치를 효과적으로 참조 할 수 있지만 개별적으로 조작 할 수 있습니다. 제어 터미널이 연결된 프로세스의 파일 디스크립터는 실제로 특정 터미널 장치를 가리 킵니다. 당신이 할 경우 이것은 분명하다
$ 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
내 현재 의사 터미널 장치는 어디에 있습니까 ? 따라서이 대상을 어떻게 든 저장할 수 있으면 터미널 화면에 TUI 상자를 계속 쓸 수 있습니다. 그게 뭐야 exec 3>&1
. command > /dev/null
예를 들어 리디렉션 을 사용 하여 명령을 호출 하면 셸은 stdout 파일 설명자를 전달한 다음 dup2()
해당 파일 설명자를에 쓰는 데 사용 합니다 /dev/null
. 이 exec
명령은 전체 셸 세션에 대해 파일 설명자 와 유사한 기능을dup2()
수행 하므로 명령이 이미 리디렉션 된 파일 설명자를 상속합니다. 와 동일합니다 exec 3>&1
. 파일 디스크립터 3
는 이제 제어 터미널을 참조 / 지시하며, 해당 쉘 세션에서 실행되는 모든 명령이 이에 대해 알 것입니다.
따라서 result=$(dialog --inputbox test 0 0 2>&1 1>&3);
쉘은 대화 상자를 작성할 파이프를 작성하지만 2>&1
먼저 명령의 파일 디스크립터 2를 해당 파이프의 쓰기 파일 디스크립터에 복제합니다 (따라서 출력이 파이프의 끝과 변수로 읽히도록합니다) 파일 디스크립터 1이 3에 복제됩니다. 그러면 파일 디스크립터 1이 여전히 제어 터미널을 참조하게되고 TUI 대화 상자가 화면에 표시됩니다.
현재 프로세스의 전류 제어 터미널에 대한 약칭이 /dev/tty
있습니다. 따라서 파일 디스크립터를 사용하지 않고 솔루션을 간단히 다음과 같이 단순화 할 수 있습니다.
result=$(dialog --inputbox test 0 0 2>&1 1>/dev/tty);
echo "$result"
기억해야 할 주요 사항 :
- 파일 디스크립터는 각 명령에 의해 쉘에서 상속됩니다.
- 명령 대체는 파이프로 구현됩니다.
- 복제 된 파일 디스크립터는 원래 파일 디스크립터와 동일한 위치를 참조하지만 각 파일 디스크립터를 개별적으로 조작 할 수 있습니다
또한보십시오
mktemp
명령을 사용하여 임시 파일을 작성할 수 있습니다 .