stdout 및 오류를 리디렉션할 때 >> 없이 추가가 작동합니다.

stdout 및 오류를 리디렉션할 때 >> 없이 추가가 작동합니다.

파일이 있지만 test.txt이름이 test. 내가 시도할 때

ls test test.txt > new 2>new

사용되지 않았기 때문에 new덮어쓸 것으로 예상했습니다. >>하지만 출력 파일에 이 두 내용을 추가했습니다. 왜 그럴까요?

답변1

긴 이야기 짧게 bash무엇이든 쓰기 전에 관련된 모든 파일을 열고 자릅니다. 인쇄가 시작될 때 파일이 잘렸기 때문에 (두 번) 둘 다 전송 stdout됩니다 .stderrnewbashls

이것이 bashI/O 리디렉션이 준비/처리되는 방식입니다. 명령을 >파일로 리디렉션( )하도록 요청하면 bash기본적으로 파일이 열리고 필요하면 생성됩니다. 파일이 이미 존재하는 경우 잘립니다. 귀하의 경우 이는 open시스템 호출과 일부 플래그를 통해 수행됩니다.

open("new", O_WRONLY|O_CREAT|O_TRUNC, 0666)

O_CREAT파일이 없으면 생성하고, O_TRUNC있으면 자릅니다. 이 시스템 호출은 open리디렉션 초기화의 일부입니다. 즉, 다음과 같은 여러 리디렉션 작업을 사용할 때...bash

$ ls test test.txt > new 2>new

... bash모든 관련 파일을 여는 것부터 시작하세요. 따라서 실행하기 전에 동일한 플래그로 두 번 열립니다 ls.new

open("new", O_WRONLY|O_CREAT|O_TRUNC, 0666)
open("new", O_WRONLY|O_CREAT|O_TRUNC, 0666)

즉, 기본적으로 명령을 실행할 때 bash다음 작업이 순서대로 수행됩니다.

  1. 표준 출력으로 열고 new필요한 경우 파일을 생성/자릅니다.
  2. 표준 오류로 열고 new필요한 경우 파일을 생성/자릅니다.
  3. 실행 ls: 내용을 작성합니다 new.

보시다시피 bash관련된 모든 파일이 잘립니다.앞으로start 를 사용하여 ls무언가를 실행할 때 를 의미합니다.... >new 2>newnew그 다음에, 출력이 해당 위치로 리디렉션됩니다. 원하는 동작을 위해서는 stdout 및 stderr을 독립적으로 bash캡처 ls하고 쓰기 전에 하나씩 열어야 합니다. 원래:

  1. 시작 ls.
  2. 무슨 일이 생기면 stdout열어서 new잘라서 쓰세요.
  3. 무슨 일이 생기면 stderr다시 열어서 new잘라서 쓰세요.

그러나 메시지는 서로 얽혀 있을 수 있습니다. 리디렉션된 프로그램은 에 무언가를 쓴 stdout다음 다른 것에 쓴 stderr다음 다시 돌아올 것입니다 stdout. 이 모든 것을 관리하는 것은 끔찍할 것입니다.(이로 인해 바람직하지 않은(정의되지 않은?) 동작이 발생할 수 있습니다...).

답변2

이 두 개를 추가하지 마세요. 이상한 결과가 나타납니다.

$ ls testasdasd qtsingleapp-homecu-bcbf-3e8 >new 2>new
$ cat new
qtsingleapp-homecu-bcbf-3e8
: No such file or directory

이 두 가지가 있으면 다음이 표시됩니다.

$ ls testasdasd qtsingleapp-homecu-bcbf-3e8 >new 2>&1
$ cat new
ls: cannot access testasdasd: No such file or directory
qtsingleapp-homecu-bcbf-3e8

그럼 strace무슨 일이 일어나고 있는지 살펴 보겠습니다.

$ strace -f -e trace=open,close,write,fcntl,dup2 sh -c 'ls testasdsad qtsingleapp-homecu-bcbf-3e8 > new 2>new'
open("/etc/ld.so.cache", O_RDONLY)      = 3
close(3)                                = 0
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY) = 3
close(3)                                = 0
open("new", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
fcntl(1, F_DUPFD, 10)                   = 10
close(1)                                = 0
fcntl(10, F_SETFD, FD_CLOEXEC)          = 0
dup2(3, 1)                              = 1
close(3)                                = 0
open("new", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
fcntl(2, F_DUPFD, 10)                   = 11
close(2)                                = 0
fcntl(11, F_SETFD, FD_CLOEXEC)          = 0
dup2(3, 2)                              = 2
close(3)                                = 0
Process 7523 attached
....
[pid  7523] write(2, "ls: ", 4)         = 4
[pid  7523] write(2, "cannot access testasdsad", 24) = 24
[pid  7523] open("/usr/share/locale/en_US/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
[pid  7523] open("/usr/share/locale/en/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
[pid  7523] write(2, ": No such file or directory", 27) = 27
[pid  7523] write(2, "\n", 1)           = 1
[pid  7523] write(1, "qtsingleapp-homecu-bcbf-3e8\n", 28) = 28
[pid  7523] close(1)                    = 0
[pid  7523] close(2)                    = 0
Process 7523 detached
--- SIGCHLD (Child exited) @ 0 (0) ---
dup2(10, 1)                             = 1
close(10)                               = 0
dup2(11, 2)                             = 2
close(11)                               = 0

의 순서를 보면 다음 open을 볼 수 있습니다.fcntldup2

  • 먼저 파일이 new열리고 파일 설명자가 할당됩니다.3
  • 그런 다음 파일 설명자가 1파일 설명자로 복사 됩니다.10
  • 그런 다음 파일 설명자 3(예: file )가 파일 설명자 (예: 지금) new에 복사됩니다 .110

> new위의 모든 내용이 주문에 언급되어 있습니다. 그런 다음 동일한 순서가 발생하지만 파일 설명자의 경우 명령에 인용되어 있습니다 2.2>new

그 후에는 두 개의 파일 설명자가 있으며 10둘 다 11새 파일을 가리키며 이러한 설명자는 stderrstdout가 됩니다 ls. 실행 시 및 가 동일한 파일을 가리키며 ls덮어 쓰기 때문에 출력의 일부가 잘립니다 . stderrstdoutnewstdoutstderr

관련 정보