bash(프롬프트, 사용자 입력, 결과)의 모든 출력을 파일로 리디렉션하려고 합니다.
예:
/bin/bash > file.txt 2>&1
나는 이것이 효과가 있을 것이라고 생각했지만 프롬프트를 얻지 못했습니다. 누구든지 내가 뭘 잘못하고 있는지 말해 줄 수 있나요?
답변1
Bash는 대화형 모드에서만 프롬프트를 출력합니다. 즉, 일반적으로 터미널(Linux의 경우/dev/tty)로 출력됩니다. /dev/stdout도 아니고 /dev/stdin도 아닙니다 :)
지금은 확실하지 않지만 완전한 기능을 갖춘 tty를 사용할 수 없을 때 bash가 제한된 상호 작용 모드를 허용할 것이라고 상상할 수 있습니다. 그렇다면 나는예상되는표준 출력에 쓰라는 메시지를 표시합니다. 아직 테스트하지 않았습니다.
훌륭한 개념 증명:
(for a in some set of words; do echo $a > /dev/tty; done) 2>&1 > /dev/null
리디렉션이 없는 것처럼 1..10만 출력됩니다. 프롬프트와 마찬가지로 출력을 터미널로 직접 보냅니다(터미널이 없으면 실패함).
Tip: 모두 모아보고 싶다면 확인해 보세요.
- 스크립트(1)스크립트로 재생(SSH 클라이언트에서 실행 로그를 캡처하시겠습니까?또는스크립트 셸 녹음 재생- FAQ인 것 같습니다)
- 이것PROMPT_COMMAND 변수이를 통해 프롬프트 표시의 부작용으로 콘텐츠를 stdout으로 인쇄할 수 있습니다.
set -o xtrace
(일명set -x
등bash -x
) 일반 로깅용성명
답변2
가장 간단한 방법은
bash -i >/tmp/logfile 2>&1
명령을 입력하면 Bash는 모든 것을 쓰고 /tmp/logfile
명령을 계속 실행하지만 터미널에는 아무것도 표시되지 않습니다. 종료할 때 Ctrl+를 누르 D거나 를 입력 하여 터미널 세션을 종료할 수 있습니다 exit
.
리디렉션 없이 동일한 작업을 실행하면 stderr
hello 메시지만 파일에 기록되고 다른 모든 내용은 현재 터미널에서 실행됩니다. 따라서 bash가 프롬프트 스트림(및 다음 명령 모두)을 출력하는 것에 대한 질문에 대한 대답은 다음과 같습니다.표준 에러.
아, 그렇습니다. 이 -i
매개변수는 bash가 대화형 모드에서 실행되도록 강제합니다. 그 사람들의 말을 듣지 마세요. 이 작업을 수행하는 데 마법이 필요하지 않습니다.
답변3
프롬프트는 truss(Solaris의 경우)에 표시된 대로 stderr에 기록됩니다.
$ truss -ft write -p 10501
10501: write(2, " d", 1) = 1
10501: write(2, " a", 1) = 1
10501: write(2, " t", 1) = 1
10501: write(2, " e", 1) = 1
10501: write(2, "\n", 1) = 1
10521: write(1, " S a t u r d a y , S e".., 46) = 46
10501: Received signal #18, SIGCLD [caught]
10501: siginfo: SIGCLD CLD_EXITED pid=10521 status=0x0000
10501: write(2, " $ ", 2) = 2
답변4
대화형 모드에서 bash는 프롬프트를 stderr로 출력합니다. 다음 strace 명령은 이를 보여줍니다( --norc
다른 프롬프트를 설정하는 ~/.bashrc의 옵션이 내 사용자 정의 프롬프트를 재정의하는 것으로 해석되지 않도록 확인).
$ export PS1="MYPROMPT> "
MYPROMPT> strace -f -- bash --norc
execve("/usr/bin/bash", ["bash"], 0x7ffcd83805b0 /* 59 vars */) = 0
[...]
openat(AT_FDCWD, "/dev/tty", O_RDWR|O_NONBLOCK) = 3
[...]
ioctl(0, TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(2, TCGETS, {B38400 opost isig icanon echo ...}) = 0
[...]
write(2, "MYPROMPT> ", 10MYPROMPT> ) = 10 <----- prompt written into stderr (fd = 2)
pselect6(1, [0], NULL, NULL, NULL, {[], 8}
stdout 및 stderr을 파일로 리디렉션하는 동일한 명령은 프롬프트가 인쇄되지 않지만 쉘이 명령을 수락함을 보여줍니다.
MYPROMPT> strace -f -- bash --norc > /tmp/shout 2> /tmp/sherr
date
다른 터미널에서 파일을 봅니다. 내용은부르다예:
$ cat /tmp/shout
dim. 04 sept. 2022 16:19:24 CEST <------- Result of the date command entered above
내용은셰르예:
$ cat /tmp/sherr
execve("/usr/bin/bash", ["bash", "--norc"], 0x7ffe73ea5da8 /* 59 vars */) = 0
[...]
openat(AT_FDCWD, "/dev/tty", O_RDWR|O_NONBLOCK) = 3
[...]
ioctl(0, TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(2, TCGETS, 0x7ffc43496b30) = -1 ENOTTY (Inappropriate ioctl for device)
[...]
read(0, <-------- No prompt is displayed
그러나 -i
bash 명령줄에 옵션을 추가하는 것과 동일한 작업을 수행하는 경우:
MYPROMPT> strace -f -- bash --norc -i > /tmp/shout 2> /tmp/sherr
stderr에 프롬프트 표시:
$ cat /tmp/sherr
execve("/usr/bin/bash", ["bash", "--norc", "-i"], 0x7ffd8c1fa520 /* 59 vars */) = 0
[...]
ioctl(2, TCGETS, 0x7ffe1a8465f0) = -1 ENOTTY (Inappropriate ioctl for device)
[...]
ioctl(0, TIOCGWINSZ, {ws_row=37, ws_col=155, ws_xpixel=0, ws_ypixel=0}) = 0
[...]
write(2, "MYPROMPT> ", 10MYPROMPT> ) = 10 <------ Prompt displayed on stderr (fd = 2)
pselect6(1, [0], NULL, NULL, NULL, {[], 8}