Bash 리디렉션 구문과 그 출력을 이해해 보세요.

Bash 리디렉션 구문과 그 출력을 이해해 보세요.

저는 Linux를 처음 접했고 리디렉션이 어떻게 작동하는지 이해하려고 노력하고 있습니다.

동일한 파일로 리디렉션하기 위한 다양한 구문을 테스트했지만 모두 동일한 결과를 생성하지는 않습니다 stdout.stderr

file1예를 들어 존재하지 않는 파일 2개( 및 file2)와 존재하는 파일 2개( foofz) 를 나열하려고 하면 다음과 같습니다 .

문법 #1(리디렉션 없음):

$ ls file1 foo fz file2

이것은 터미널에서 얻는 출력입니다.

ls: cannot access file1: No such file or directory
ls: cannot access file2: No such file or directory
foo  fz

구문 #2:

이제 리디렉션을 통해:

$ ls file1 foo fz file2 > redirect 2>&1

redirect파일에는 구문 #1과 동일한 결과가 포함되어 있습니다.

ls: cannot access file1: No such file or directory
ls: cannot access file2: No such file or directory
foo
fz

따라서 위의 두 구문 모두 쉘이 stderr먼저 인쇄된 다음 stdout.

구문 #3:

이제 다음 구문 중 하나를 사용하려고 하면 다음과 같습니다.

$ ls file1 foo fz file2 > redirect 2> redirect

또는

$ ls file1 foo fz file2 2> redirect > redirect

그러면 파일 redirect에는 다음 내용이 포함됩니다.

foo
fz
nnot access file1: No such file or directory
ls: cannot access file2: No such file or directory

stdout여기서는 이전에 인쇄된 것처럼 보이지만 stderr시작 부분이 stderr동일한 문자 수로 "잘려진" 것을 볼 수 있습니다 stdout.

의 길이 stdout는 6자 ( foo fz캐리지 리턴 포함)이므로 stderr( ls: ca)의 처음 6자를 덮어씁니다 stdout. 그래서 실제로 는 붙인 것이 아니라 stderr먼저 인쇄한 다음 stdout인쇄 한 것처럼 보입니다 .stderr

stderr그러나 만약 그렇다면 나에게 더 의미가 있을 것입니다.완전히stdout부분 덮어쓰기 대신 제거하고 교체하세요 .

구문 #4:

구문 #3을 수정하는 유일한 방법은 다음에 추가 연산자를 추가하는 것입니다 stdout.

$ ls file1 foo fz file2 >> redirect 2> redirect

또는

$ ls file1 foo fz file2 2> redirect >> redirect

결과는 구문 #2와 동일합니다.

ls: cannot access file1: No such file or directory
ls: cannot access file2: No such file or directory
foo
fz

이 글은 여기구문 #3이 잘못되었음을 설명합니다(아마도 구문 #4도 틀렸을 것입니다). 그러나 논의를 위해 구문 #3이 잘못된 이유는 무엇입니까? 도대체 무슨 말을 하는 걸까요(혹은아니요Tell) 쉘이 구문 #2 이외의 다른 작업을 수행하도록 하시겠습니까?

stderr또한 출력이 항상 이전에 표시되는 이유가 있습니까 stdout?

감사합니다!

답변1

이는 동일한 파일에 동시에 쓰는 두 개의 프로세스를 실행하는 것과 같습니다. 이는 나쁜 생각입니다. 두 개의 서로 다른 열린 파일 핸들이 생기고 데이터가 왜곡될 수 있습니다(위의 #3 참조). 구문 #2를 사용하는 것이 정확합니다.하나파일 핸들을 사용하여 stderr과 stdout을 동일한 위치로 가리킵니다.

stderr이 항상 먼저 인쇄된다는 규칙은 없습니다. 나는 ls이것이 ls특정 파일이 존재하지 않는다는 것을 실제로 선언하기 전에 디렉토리의 모든 항목을 검사해야 하기 때문이라고 생각합니다 . 따라서 디렉터리 테이블을 통해 N번 패스하는 대신 단일 패스를 만들고 지정된 모든 명령줄 인수를 확인하고 오류를 보고하고 발견된 파일을 인쇄합니다. 다른 명령은 stdout 다음에 stderr로 인쇄할 수도 있고, 심지어 그 사이를 번갈아 가며 인쇄할 수도 있습니다.

답변2

stdout일반적으로 버퍼링(나중에 기록하기 위해 메모리에 저장) stderr되거나 절대로(무언가 기록되기 전에 프로그램이 충돌하더라도 오류 메시지가 표시되기를 원함) 와일드카드 응답에 추가합니다. 그래서 stderr보통 더 일찍 옵니다.

답변3

여기는 개발자나 커널 전문가가 아닙니다. 따라서 코드에 대해 언급할 수는 없지만 구문 #3에서는 두 개의 서로 다른 파이프를 사용하여 동일한 파일 stdout에 파이프를 연결하고 있습니다. stderr따라서 두 출력을 모두 보내는 공통 파일에는 두 개의 다른 파이프에서 리소스 경합 문제가 있을 수 있습니다. 운영 체제의 비실시간 특성을 고려하면 두 파이프라인이 동시에 동일한 파일에 정보를 입력할 수 있습니다. 이는 누락된 문자를 설명할 수 있습니다.

구문 #2에서는 파일에 파이프가 들어오고 쉘이 경쟁 조건에 따라 파이프를 관리하는 stderr동일한 파이프로 리디렉션합니다 .stdout

이것은 제가 경험한 추측이며 단지 추측일 뿐입니다. 이를 확인할 수 있는 것은 없습니다.

관련 정보