파일 디스크립터 사본없이 stdout 및 stderr을 동일한 파일로 경로 재지 정하는 것이 안전합니까?


27

빈 디렉토리에서 시작합니다.

$ touch aFile
$ ls
aFile

그런 다음 ls두 가지 주장 중 하나는이 디렉토리에 없습니다. 두 출력 스트림을 모두라는 파일로 리디렉션합니다 output. 나는 >>동시에 쓰는 것을 피하기 위해 사용 합니다.

$ ls aFile not_exist >>output 2>>output
$ cat output
ls: cannot access 'not_exist': No such file or directory
aFile

작동하는 것 같습니다. 이 접근 방식에 위험이 있습니까?


6
그것은 빠른 투표였습니다. 5 초 정도 걸렸습니다. 내 질문의 가치를 그렇게 빨리 평가할 수있는 방법을 알려줄 수 있습니까? 더 나은 아직, 내가 그것을 향상시킬 수있는 무엇이 잘못입니까?
exit_status

왜 더 표준을 사용하지 ls aFile not_exist &>>output않습니까? (참고로, bash 를 사용한다고 가정합니다 .)
FedonKadifeli

5
그것이 내가 요구하는 것을 이해하는 데 도움이되지 않기 때문입니다. 이 스트림을 동일한 파일로 리디렉션하는 방법을 알고 있습니다. 내가 알고 싶은 것은 질문에서 제안한 내용에 문제가 있는지 여부입니다. @FedonKadifeli
exit_status

1
@FedonKadifeli &>>은 표준이 아닙니다. 다른 쉘에서 다르게 작동하는 DEPRECATED, 모호한 구문입니다. 너희들이 어디서 물건을 가져 오는지 궁금해.
Billy 삼촌

4
배쉬는 표준 이 아니다 . POSIX 표준 ls &>>foo ...은 두 개의 쉼표로 구문 분석 해야하는 명령 ls &이며 >>foo ...및 이것은 /bin/sh우분투의 다른 쉘 이 구문 분석하는 방식입니다. 더 이상 사용되지 않기 때문에 여기 를 볼 수 있습니다. 하지만 나는 그것이 어떤 종류의 권위인지 척하지는 않습니다. 그래도 bash유지 보수 담당자에게 좋은 아이디어를 사용할 것인지 물을 수 있습니다 .
Billy 삼촌

답변:


22

아니요, 표준만큼 안전하지는 않습니다 >>bar 2>&1.

글을 쓸 때

foo >>bar 2>>bar

을 사용하여 bar파일을 두 번 열어 각각 O_APPEND독립적 인 상태 (포인터, 열린 모드 등)를 가진 두 개의 완전히 독립적 인 파일 객체 [1]를 만듭니다.

이것은 시스템 호출을 2>&1호출하는 것과 매우 다르며 dup(2)stderr 및 stdout을 동일한 파일 객체에 대해 상호 교환 가능한 별명으로 만듭니다.

이제 문제가 있습니다.

O_APPEND둘 이상의 프로세스가 한 번에 파일에 데이터를 추가하는 경우 NFS 파일 시스템에서 파일이 손상 될 수 있습니다. NFS는 파일 추가를 지원하지 않기 때문에 클라이언트 커널이 파일을 시뮬레이션해야하므로 경쟁 조건 없이는 수행 할 수 없습니다.

당신은 일반적으로 같은 파일의 확률에 의지 할 수 bar있는 foo >>bar 2>&1매우 낮은 것으로 두 개의 별도의 장소에서 같은 시간에 기록된다. 그러나 >>bar 2>>bar당신은 아무 이유없이 그것을 수십 배나 늘 렸습니다.

[1] POSIX lingo의 "파일 설명 열기"


3
추가 모드 파일의 경우 공식적으로 안전 합니다. 인용 된 문제는 NFS 에서 버그 로 인해 파일 시스템으로 적합하지 않은 (POS가 아닌) 것입니다. 비추가 모드의 경우 안전하지 않습니다.
R ..

1
그것은 중요하지 않습니다. OP의 이중 추가는 사용하기에 안전 하지 않습니다 (완전히 무의미 함). 그리고 O_APPEND어쨌든 서투른의 종류 - 제대로 구현하기가 꽤 부담.
mosvy

NFS 경쟁 조건은 서로 다른 클라이언트 사이에서만 발생한다고 생각합니다. 클라이언트 OS는 프로세스 간 모든 쓰기를 조정해야합니다.
Barmar

@Barmar는 클라이언트 OS가 nfs 파일에 대한 자체 뷰만 신경 쓰면 사실입니다. 그러나로 열린 nfs 파일에 쓸 때 O_APPEND클라이언트는 먼저 서버에서 파일의 "실제"크기를 검색 한 다음 (아이 노드를 "검증") 탐색 + 쓰기 + 캐시 된 아이 노드 업데이트를 수행합니다. 마지막 부분 만 잠금 상태에서 수행됩니다. 즉, 첫 번째 부분은 여전히 ​​서버에서 오래된 크기를 검색하고 로컬 / 캐시 된 inode에서 올바른 크기를 무시할 수 있습니다. 와 같은 문제입니다 lseek(SEEK_END).
mosvy

동일한 클라이언트에서 두 스트림간에 경쟁 조건이 어떻게 발생할 수 있는지 여전히 알 수 없습니다. 두 스트림 모두 동일한 로컬 캐시 된 inode를 참조해야합니다.
Barmar

22

당신이 할 때 어떻게됩니까

some_command >>file 2>>file

file두 번 추가를 위해 열립니다. 이것은 POSIX 파일 시스템에서 수행하는 것이 안전합니다. 추가를 위해 파일을 열 때 파일에 발생하는 모든 쓰기는 데이터가 표준 출력 스트림 또는 표준 오류 스트림을 통해 전달되는지 여부에 관계없이 파일 끝에서 발생합니다.

이것은 기본 파일 시스템에서 원자 추가 쓰기 작업에 대한 지원에 의존합니다. NFS와 같은 일부 파일 시스템은 원자 추가를 지원하지 않습니다. 예를 들어 StackOverflow에서 "UNIX에서 파일을 추가합니까?" 라는 질문을 참조하십시오 .

사용

some_command >>file 2>&1

그래도 NFS에서도 작동합니다.

그러나

some_command >file 2>file

셸이 출력 파일을 잘라 내고 (두 번) 스트림에서 발생하는 모든 쓰기 는 다른 스트림에서 이미 쓴 데이터 를 덮어 씁니다 .

예:

$ { echo hello; echo abc >&2; } >file 2>file
$ cat file
abc
o

hello문자열 (종단으로 바꿈) 먼저 기록되고, 다음 스트링 abc개행 다음은 덮어, 표준 오차로 기록한다 hell. 결과는 abc줄 바꿈 이있는 문자열 이고, 첫 번째 echo출력 의 왼쪽에 o줄 바꿈이 있습니다.

그 줄이 마지막에 쓰여지고 줄 보다 길기 때문에 두 개의 echo상처를 바꾸는 것은 hello출력 파일 에서만 생성됩니다 abc. 리디렉션이 발생하는 순서는 중요하지 않습니다.

더 관용적 인 것을 사용하는 것이 더 좋고 안전합니다.

some_command >file 2>&1

1
즉, (보른 또는 톰슨 쉘의 경우 아니었다 현대 쉘의 사실이지만 >>에서 유래), >>끝으로 쓰기 위해 열고 추구하는 것 (O_APPEND 후 아직 다시 발명되지 않았기 때문에 나는 가정). 심지어 Solaris 10에서 /bin/sh -c '(echo a; echo b >&2) >> file 2>> file; cat file'출력합니다 b.
Stéphane Chazelas

@ StéphaneChazelas Solaris 10의 구현 sh또는 파일 시스템에 문제가 있습니까?
Kusalananda

1
그것이 >>원래하고 있던 일이며, O_APPEND로 열리지 않고 끝없이 열리고있었습니다. 그다지 큰 문제는 아닙니다. 그것이하고있는 것과 문서화 된 것입니다.
Stéphane Chazelas

0

그것은 당신이 달성하고자하는 것에 달려 있습니다. 출력과 같은 파일에 오류가 있는지 확인하는 것은 사용자의 몫입니다. 이것은 쉘의 기능으로 파일에 텍스트를 저장하여 원하는대로 리디렉션 할 수 있습니다. 절대적으로 예 또는 아니오는 없습니다. 리눅스의 모든 것이 여러 가지 방법으로 수행 될 수 있으므로 이것이 내 방법 ls notExistingFile existingFile >> output 2>&1 입니다. 리디렉션 자체 측면에서 완벽하게 안전합니다.


여기서 말하는 것보다 더 많은 것이 있습니다. >대신에 동일한 연습으로 >>일부 문자를 덮어 씁니다. 따라서 쉘로 리디렉션 할 수있는 것은 아닙니다.로 리디렉션 할 때 >결과가 다르기 때문입니다. 으로 뉘앙스 >>>있습니까?
exit_status

예, 다를 것입니다. 내가 말했듯이 그것은 당신의 목표 >덮어 쓰기 에 달려 있습니다 . >>추가
천사
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.