Linux의 파이핑/리디렉션은 정확히 어떻게 작동합니까?

Linux의 파이핑/리디렉션은 정확히 어떻게 작동합니까?

stdin/stdout 리디렉션의 세 가지 예가 있는데 그 중 하나만 의도한 대로 작동하고 있습니다. 누군가가 나에게 그것을 설명할 수 있다면 좋겠습니다.

목표는 file1의 내용을 정렬하고 변경 사항을 동일한 파일에 저장하는 것입니다.

  1. 파일1 정렬 | tee file1 > /dev/null --------> 작동합니다

  2. 파일1 정렬 | tee file1 --------> file1의 내용이 삭제됩니다.

  3. 파일1 정렬 | tee file1 > file2 --------> file1의 내용이 삭제됩니다.

추신. tee는 표준 입력을 각 FILE과 표준 출력에 복사합니다.

첫 번째 예제가 작동하는 이유는 무엇입니까?

답변1

Debian Wheezy에 대한 내 테스트에 따르면 세 가지 시나리오 모두 두 가지 결과로 이어질 수 있습니다(file1이 정렬되어 자체적으로 다시 기록되거나 아무것도 정렬되지 않고 file1에 아무것도 기록되지 않습니다).

나는 이것이 정상적인 동작이며 Linux가 파일을 사용하는 방식에서 비롯된 것이라고 믿습니다. 명령에 대해 생각해 보십시오. sort 명령은 file1을 읽기 시작하고 즉시 출력을 tee로 보냅니다. Tee는 출력을 읽고 이를 file1에 다시 쓴 다음 /dev/null에 인쇄합니다. 전체 파일을 읽을 수 있을 만큼 정렬 속도가 빠른 경우1, tee는 정렬된 출력을 얻습니다. 그러나 tee가 파일에 대한 잠금을 얻으면 해당 파일을 지우고(추가 옵션이 사용되는 경우를 제외하고 tee는 항상 출력 파일을 지웁니다) 이는 3가지 시나리오 모두에서 일어나는 일입니다.

더 짧게 만들기 위해 때로는 정렬이 file1을 읽을 만큼 빠르지 않다고 가정해 보겠습니다. 이러한 경우 tee는 sort가 파일을 읽을 수 있기 전에 파일을 지웁니다.

다음 절차를 권장합니다.

cat file1 | sort > /tmp/sorting.tmp; mv /tmp/sorting.tmp file1

stdout에서 정렬된 출력을 보려면 다음과 같이 하십시오.

cat file1 | sort | tee /tmp/sorting.tmp; mv /tmp/sorting.tmp file1

다중 프로세서 시스템에서 하나의 파일에 대해 2개의 다른 명령을 사용하는 것은 좋은 생각이 아닙니다. 어느 명령이 먼저 실행되는지 확신할 수 없습니다. 단일 스레드 시스템에서는 동작이 순차적으로 달라집니다.

답변2

나는 그 행동이 예측 가능하다고 의심합니다(그리고 확실히 그것에 의존하지 않을 것입니다). 명령 은 tee아마도 입력을 '다른' 대상으로 보내기 위해 새 프로세스를 시작합니다. 운영 체제는 대상 파일을 생성하고 임시 버퍼를 파일에 쓰는 지점에 도달할 때까지 출력을 '버퍼링'합니다. 이런 일이 발생하고 소스를 덮어쓰는 정확한 순간은 다음 사항에 따라 달라집니다.

  • 파일 크기 및 버퍼에 사용 가능한 메모리
  • 경과 시간
  • 파이프에서 입력이 tee완료 되면

이것은 다음보다 더 깊습니다 bash. 프로그램이 시작되는 방식입니다 bash. 쉘은 사용자가 입력한 명령을 해석하고 명령을 실행하는 데 필요한 프로그램을 시작합니다. 쉘은 각 프로그램이 작동하는 방식을 제어할 수 없으며 해당 프로그램이 상호 작용하는 방식도 제어할 수 없습니다. 프로그램(또는 프로그램 세트)에 입력 파일에서 데이터를 가져와 동일한 문장으로 동일한 입력 파일에 대한 결과를 쓰도록 요청하는 것은 사용자의 책임입니다.

bash는 사용자 명령의 해석자일 뿐이라는 점을 잊지 마십시오. shell사용자 의도를 시스템 호출로 변환하는 것은 운영 체제 주변에 있을 뿐입니다.

그리고 그것은문서화, 도! 또는이 메일, 유사한 문제를 해결합니다. 아니면 이거StackOverflow 스레드. 또는이 Serverfault 스레드.

stdin파일에서 입력 명령을 받는 경우 : 의 리디렉션에서도 이런 일이 발생할 수 있습니다 $ myprog < commandfile. 명령 파일에 쓰는 경우 모든 의 명령이 실행된다는 myprog보장은 없습니다 .commandfile

정말 기본적인 비유는 다음 명령 목록과 같습니다.

- Execute the instructions step by step
- Dip this instruction list in a bucket of black paint
- Type in the following commands:
  find /etc -type f -exec cat '{}' \; | tr -c '.[:digit:]' '\n' \
  | grep '^[^.][^.]*\.[^.][^.]*\.[^.][^.]*\.[^.][^.]*$'

먼저 복사를 하시면 될 것 같은데요? (다음에서 가져온 명령고급 Bash 스크립팅 가이드)

답변3

그렇다면 파일에 변경 사항을 추가하면서 파일의 원래 내용을 유지하고 싶습니까?

tee는 기본적으로 덮어쓰기를 수행하므로 -a 플래그를 사용하여 파일에 변경 사항을 추가해 보세요.

답변4

sort file1 | tee file1 > tmp && mv file1 original && mv tmp file1

자리 표시자에 파일을 쓰고 원본 이름을 백업으로 바꾼 다음 자리 표시자를 원본으로 이동할 수 있습니다.

관련 정보