왜 / dev / null이 파일입니까? 왜 그 기능이 간단한 프로그램으로 구현되지 않습니까?


114

Linux의 특수 파일 개념을 이해하려고합니다. 그러나 특수 파일 /dev을 C에있는 몇 줄로 구현할 수있을 때 어리석은 것처럼 보입니다.

또한 null로 리디렉션하는 대신 파이핑하는 것과 거의 같은 방식으로 사용할 수 있습니다 /dev/null. 파일로 사용하는 특별한 이유가 있습니까? 파일을 파일로 만들지 않으면 같은 파일에 너무 많은 프로그램에 액세스하는 등 다른 많은 문제가 발생합니까?


20
왜 덧붙여, 이러한 오버 헤드의 대부분은 또한 cat foo | bar보다 (규모) 훨씬 더 나쁘다 bar <foo. cat사소한 프로그램이지만 사소한 프로그램조차도 비용을 발생시킵니다 (일부 FIFO 시맨틱에 특정)-프로그램이 seek()FIFO 내부에 있을 수 없으므로 , 예를 들어 탐색으로 효율적으로 구현할 수있는 프로그램은 훨씬 더 비싼 작업을 수행 할 수 있기 때문에 파이프 라인이 주어 졌을 때, 캐릭터 디바이스를 사용 /dev/null하면 그러한 조작을 위조하거나 실제 파일을 사용하여이를 구현할 수 있지만 FIFO는 컨텍스트 인식을 처리 할 수 ​​없습니다).
— Charles Duffy

13
grep blablubb file.txt 2>/dev/null && dosomething프로그램 또는 함수 인 null과 함께 작동 할 수 없습니다.
— rexkogitans

16
계획 9 운영 체제에 대해 읽어 보면 "모든 것이 파일"이라는 비전이 어디로 가고 있는지 알아볼 수 있습니다. 리소스를 파일로 사용할 수있는 힘을 좀 더 쉽게 볼 수 있습니다. 일단 현대 리눅스 / 유닉스처럼 대부분 / 부분적으로가 아니라 개념을 완전히 수용하는 시스템을 본다면
— mtraceur

25
뿐만 아니라 아무도 커널 공간에서 실행되는 장치 드라이버가 있음을 지적하지 않기 때문에 이다 "C 라인의 소수"와 프로그램 , 답변 중 어느 것도 지금까지 실제로 "같은 파일에 액세스 너무 많은 프로그램"의 상상을 해결 없었다 질문에.
— JdeBP

12
당신은 그것을 믿지 않을 것 있지만 : 다시 "그 기능은 C에서 라인의 소수에 의해 구현 될 수있다" 되는 C의 행의 소수에 의해 구현! 예를 들어, read함수 의 본문은 /dev/null"return 0"으로 구성됩니다 (이것은 아무것도하지 않으며 EOF가 발생 함을 의미합니다). (정적 github.com/torvalds/linux/blob/master/ drivers / char / mem.c ) ssize_t read_null(struct file *file, char __user *buf, size_t count, loff_t *ppos) { return 0; }(아, @JdeBP가 이미 그 점을 지적했음을 알 수 있습니다. 어쨌든, 여기에 그림이 있습니다 :-).
— 피터 A. 슈나이더

답변:


153

캐릭터 전용 장치를 사용함으로써 얻을 수있는 성능 이점 외에도 주요 이점은 모듈성 입니다. / dev / null은 셸 파이프 라인뿐만 아니라 파일이 필요한 거의 모든 컨텍스트에서 사용될 수 있습니다. 파일을 명령 행 매개 변수로 승인하는 프로그램을 고려하십시오.

# We don't care about log output.
$ frobify --log-file=/dev/null

# We are not interested in the compiled binary, just seeing if there are errors.
$ gcc foo.c -o /dev/null  || echo "foo.c does not compile!".

# Easy way to force an empty list of exceptions.
$ start_firewall --exception_list=/dev/null

프로그램을 소스 또는 싱크로 사용하는 것이 매우 번거로운 경우입니다. 쉘 파이프 라인의 경우에도 stdout과 stderr는 독립적으로 파일로 리디렉션 될 수 있습니다.

# Suppress errors, but print output.
$ grep foo * 2>/dev/null

14
또한 /dev/null쉘 명령에서만 사용하지 마십시오 . 소프트웨어에 제공된 다른 매개 변수 (예 : 구성 파일)에서이 매개 변수를 사용할 수 있습니다. --- 소프트웨어를 포트하는 것이 매우 편리합니다. /dev/null일반 파일과 차이를 만들 필요는 없습니다 .
— pabouk

실행 파일을 싱크하기위한 별도의 리디렉션에 대한 부분을 이해하기가 어렵습니다. C에서는 연결을 설정 하는 호출을 변경하여 다른 프로세스 배관 과 마찬가지로 pipe,을 수행 합니까? 그것은 우리가 너무 많은 장치와 같은 파일 패턴을 가지고 있지 않았고에서 일 대부분의 경우 대부분의 포탄하지만 아마도, 그렇게 할 수있는 예쁜 방법을 제공하지 않는 사실 및 실행 파일로 취급하고, 껍질이 방법으로 설계되었을 것입니다 지금 리디렉션하는 것처럼 쉽게 할 수 있습니다. forkexecvedup2/dev/proc
— aschepler

6
@aschepler 싱크 실행 파일로 리디렉션하지 않는 것은 어렵습니다. 널 싱크가 파일이 아닌 경우 두 파일 과 널 싱크 에서 쓰거나 읽을 수있는 응용 프로그램을 작성하는 것이 더 복잡합니다. 모든 것이 파일이 아닌 세상에 대해 이야기하지 않는 한 모든 것이 실행 가능한가? * nix OS와는 매우 다른 모델입니다.
— 큐빅

1
@aschepler 잊어 버렸습니다 wait4! POSIX api를 사용하여 stdout과 stderr을 다른 프로그램으로 파이프하는 것이 가능하며 stdout과 stderr을 다른 명령으로 리디렉션하기위한 영리한 쉘 구문을 발명 할 수 있습니다. 그러나 지금은 그러한 쉘을 알지 못합니다. 더 큰 요점은 / dev / null이 기존 도구 (파일과 함께 작동하는)에 깔끔하게 맞고 / bin / null은 그렇지 않다는 것입니다. 우리는 또한 gcc가 파일처럼 프로그램으로 출력을 쉽게 (안전하게!) 만드는 IO API를 상상할 수있다. 그러나 그것은 우리가 처한 상황이 아니다.
— ioctl

2
껍질에 관한 @ioctl; 등의 작업을 수행 할 수있게됩니다 적어도 zsh을하고 bash는 모두 grep localhost /dev/ /etc/hosts 2> >(sed 's/^/STDERR:/' > errfile ) > >(sed 's/^/STDOUT:/' > outfile)별도로 처리 결과적 errfile와outfile
— 마티 Nalis을

62

공평하게, 그것은 그 자체 로 정규 파일 이 아닙니다 . 그것은 문자 특수 장치입니다 :

$ file /dev/null
/dev/null: character special (3/2)

파일이나 프로그램이 아닌 장치로 작동한다는 것은 입력 / 출력을 표준 입력 / 출력 / 오류를 포함한 모든 파일 디스크립터에 첨부 할 수 있으므로 입력 또는 출력을 리디렉션하는 작업이 더 간단하다는 것을 의미합니다.


24
cat file | null파이프를 설정하고, 프로세스를 생성하고, 새로운 프로세스에서 "널 (null)"을 실행하는 등 많은 오버 헤드가 발생합니다. 또한 null자체적으로 버퍼에 바이트를 읽는 루프에서 꽤 많은 CPU를 그냥 버렸다 ... /dev/null커널에서 구현하는 것이 더 효율적이다. 또한 /dev/null리디렉션 대신 인수 로 전달하려면 어떻게해야 합니까? (당신은 <(...)bash에서 사용할 수 있지만 훨씬 더 무거운 방법입니다!)
— filbranden

4
로 null리디렉션을 사용하는 대신 이름이 지정된 프로그램으로 파이프 /dev/null해야하는 경우, stderr 만 null로 보내면서 프로그램을 실행하도록 쉘에 간단하고 명확한 방법이 있습니까?
— Mark Plotnick

5
이것은 오버 헤드 데모를위한 정말 비싼 설정입니다. /dev/zero대신 사용 하는 것이 좋습니다 .
— chrylis

20
그 예는 잘못되었습니다. dd of=-이라는 파일 에 쓰려면 기본적으로 쓰는 위치이므로 stdout에 쓰려면 -생략하십시오 . stdin을 읽지 못하는 것처럼 파이프가 작동 하지 않으므로 SIGPIPE로 종료됩니다. 입력을 버리는 명령에 대해서는 ...을 사용할 수 있습니다 . 또한 병목과 관련이없는 비교는 아마도 난수 생성 일 것입니다. of=ddfalsefalseddcat > /dev/null
— Stéphane Chazelas

8
AST 버전 dd등은 대상이 / dev / null임을 감지했을 때 쓰기 시스템 호출을 방해하지 않습니다.
— Mark Plotnick

54

유닉스 (그리고 결과적으로 리눅스)를 형성 한 비전 / 디자인과 많은 관련이있는 이유 와 그로 인한 장점을 의심합니다 .

의심 할 여지없이 여분의 프로세스를 시작하지 않으면 무시할 수없는 성능상의 이점이 있지만 더 많은 것으로 생각됩니다. Early Unix는 "모든 것이 파일입니다"라는 은유를 가지고 있습니다. 쉘 스크립팅 관점이 아니라 시스템 관점에서 볼 수 있습니다.

null명령 행 프로그램과 /dev/null장치 노드 가 있다고 가정 하십시오. 쉘 스크립팅의 관점에서 foo | null프로그램은 실제로 진정입니다 유용 하고 편리 하고, foo >/dev/null입력 작은 조금 오래 걸리고 이상하게 보일 수있다.

그러나 두 가지 연습이 있습니다.

  1. null기존 유닉스 도구를 사용하여 /dev/null쉽게 프로그램 을 구현해 봅시다 : cat >/dev/null. 끝난.

  2. 당신 /dev/null은 측면에서 구현할 수 있습니까 null?

입력을 버리는 C 코드가 사소한 것이므로 타스크에 가상 파일을 제공하는 것이 왜 유용한 지 아직 명확하지 않을 수 있습니다.

고려해보십시오 : 거의 모든 프로그래밍 언어 는 파일, 파일 디스크립터 및 파일 경로와 함께 작동 해야합니다. Unix의 "모든 것이 파일"패러다임의 일부이기 때문입니다.

stdout에 쓰는 프로그램 만 있으면 모든 쓰기를 삼키는 가상 파일이나 파이프를 모든 쓰기를 삼키는 프로그램으로 파이프를 재지 정하는 것은 문제가되지 않습니다.

이제 데이터를 읽거나 쓰는 데 파일 경로를 사용하는 프로그램 (대부분의 프로그램)이 있고 해당 프로그램에 "공백 입력"또는 "이 출력 폐기"기능을 추가하려는 /dev/null경우 무료로 제공됩니다.

그것의 우아함은 모든 관련 프로그램의 코드 복잡성을 줄이는 것입니다-시스템이 실제 "파일 이름"을 가진 "파일"로 제공 할 수있는 일반적인 일반적인 사용 사례마다 코드가 사용자 정의 명령을 추가하지 않아도됩니다 처리 할 라인 옵션 및 사용자 정의 코드 경로.

좋은 소프트웨어 엔지니어링은 종종 생각하기 쉬워 지지만 유연하게 유지 되는 방식으로 문제의 일부 요소를 추상화하기위한 좋은 또는 "자연적인"은유를 찾는 데 의존 하기 때문에 기본적으로 동일한 수준의 상위 수준 문제를 해결할 필요가 없습니다. 동일한 하위 수준의 문제에 대한 솔루션을 지속적으로 다시 구현하는 데 시간과 정신 에너지를 소비합니다.

자원에 액세스하기위한 하나의 은유 것 같다 "모든 파일입니다"당신은 호출 open객체에 대한 참조 (파일 기술자)를 받고하는 계층 구조로 네임 스페이스에 지정된 경로로, 당신은 할 수 read및 write파일 설명에 등. stdin / stdout / stderr은 방금 미리 열린 파일 설명자입니다. 파이프는 파일과 파일 설명 자일 뿐이며 파일 리디렉션을 사용하면 이러한 모든 부분을 서로 붙일 수 있습니다.

유닉스는 이러한 추상화가 얼마나 잘 작동했는지에 따라 부분적으로 성공했으며 /dev/null그 전체의 일부로 가장 잘 이해됩니다.


추신 : "모든 것이 파일입니다"라는 유닉스 버전 /dev/null과 그 뒤에 나오는 많은 시스템에서 구현 된 은유의보다 유연하고 강력한 일반화를 향한 첫 단계 와 같은 것들을 살펴볼 가치가 있습니다.

예를 들어, 유닉스에서 특별한 파일과 같은 객체 /dev/null는 커널 자체에서 구현되어야했지만, 그 이후로 프로그램을위한 방법을 제공하는 여러 시스템이 만들어진 파일 / 폴더 형태로 기능을 노출하는 것이 유용하다는 것이 밝혀졌습니다 하기 위해서.

첫 번째는 Unix를 만든 동일한 사람들이 만든 Plan 9 운영 체제였습니다. 나중에 GNU Hurd는 "번역자"와 비슷한 일을했습니다. 한편 리눅스는 결국 FUSE (다른 주류 시스템에도 확산 됨)를 얻었습니다.


8
@PeterCordes는 디자인을 이해하지 못하는 위치에서 출발합니다. 모두가 이미 디자인을 이해했다면이 질문은 존재하지 않을 것입니다.
— OrangeDog

1
@ mtraceur : 루트 권한없이 이미지 파일을 마운트 하시겠습니까? 퓨즈에 루트가 필요하지 않을 수도 있지만 확실하지 않습니다.
— Peter Cordes

1
@PeterCordes RE : "이상한 것으로 보임": 디자인에 대한 사과가 아니며, 시스템 구현에 대해 생각하지 않고 시스템에 대한 유레카 순간을 보지 못한 경우 어떻게 보일지에 대한 인정입니다. 넓은 디자인 이점. 나는 "쉘 스크립팅 관점에서"로 문장을 열고, 몇 문장 전에 시스템 관점과 시스템 관점의 대조를 암시함으로써 그것을 명확하게하려고 노력했다. 더 이상 생각하면 "이상하게 보일 수 있습니다"가 더 낫습니다. 너무 자세하게 표현하지 않고 더 명확하게 표현할 수있는 추가 단어 제안을 환영합니다.
— mtraceur

2
내가 유닉스와 관련하여 젊은 엔지니어로 들었던 첫 번째 것은 "Everything Is A File"이었고 나는 여러분이 수도를들을 수 있다고 맹세합니다. 그리고 그 아이디어를 조기에 받아들이면 유닉스 / 리눅스가 이해하기 훨씬 쉬워 보입니다. 리눅스는 그 디자인 철학의 대부분을 물려 받았습니다. 누군가 언급 한 것이 기쁘다.
— StephenG

2
@PeterCordes, DOS NUL는 모든 파일 이름에 매직 파일 이름이 나타나 도록하여 입력 문제를 "해결했습니다" > NUL.
— Cristian Ciupitu

15

내가 생각하는 /dev/nullA는 문자 장치 (즉, 일반 파일처럼 동작) 대신에 대한 programm에 성능 이유는 .

프로그램 인 경우 프로그램을로드, 시작, 스케줄링, 실행 한 후 프로그램을 중지 및 언로드해야합니다. 설명하는 간단한 C 프로그램은 많은 리소스를 소비하지는 않지만 프로세스 관리 작업이 대규모로 비용이 많이 들기 때문에 많은 수의 (예 : 수백만) 리디렉션 / 배관 작업을 고려할 때 큰 차이가 있다고 생각합니다. 여기에는 컨텍스트 전환이 포함됩니다.

또 다른 가정 : 프로그램에 파이핑하려면 수신 프로그램 이 메모리를 할당 해야합니다 ( 메모리 는 나중에 직접 폐기하더라도). 따라서 공구에 파이프를 연결하면 송신 프로그램과 수신 프로그램에서 두 번의 메모리 소비가 발생합니다.


10
설치 비용뿐만 아니라 파이프에 쓸 때마다 메모리 복사가 필요하고 읽기 프로그램으로 전환하는 컨텍스트가 필요합니다. (또는 파이프 버퍼가 가득 찼을 때 컨텍스트 전환이 필요합니다. 그리고 독자는 read데이터가 있을 때 다른 사본을 작성해야 합니다). 유닉스가 설계된 단일 코어 PDP-11에서는 무시할 수 없습니다! 메모리 대역폭 / 복사는 오늘날보다 훨씬 저렴합니다. writeFD 열기에 대한 시스템 호출 /dev/null은 버퍼에서 데이터를 읽지 않아도 즉시 반환 될 수 있습니다.
— 피터 코 데스

@ PeterCordes, 내 노트는 접선이지만 역설적으로 오늘날의 메모리 쓰기가 그 어느 때보 다 비쌀 수 있습니다. 8 코어 CPU는 클럭 시간에 16 개의 정수 연산을 수행하는 반면 엔드 투 엔드 메모리 쓰기는 16 클럭 (4GHz CPU, 250MHz RAM)으로 완료됩니다. 256의 요소입니다. 최신 CPU의 RAM은 PRL-11 CPU의 RL02와 비슷하며 주변 장치 저장 장치와 거의 같습니다! :) 간단하고 자연 스럽지는 않지만 캐시에 충돌하는 모든 내용이 기록되며 쓸모없는 쓰기는 항상 중요한 캐시 공간에 대한 다른 계산을 박탈합니다.
— kkm

@kkm : 예, 커널의 파이프 버퍼에 약 2x 128kiB의 L3 캐시 풋 프린트를 낭비하고 null프로그램 의 읽기 버퍼가 빨라지 지만 대부분의 멀티 코어 CPU는 항상 모든 코어를 사용하지 않고 실행되지 않습니다. null프로그램 을 실행하는 CPU 시간 은 대부분 비어 있습니다. 모든 코어가 막힌 시스템에서는 쓸모없는 배관이 더 큰 문제입니다. 그러나 "핫"버퍼는 RAM으로 플러시되지 않고 여러 번 다시 작성할 수 있으므로 캐시가 아닌 L3 대역폭에 대해서만 경쟁하고 있습니다. 특히 동일한 물리적 시스템의 다른 논리 코어가 경쟁하는 SMT (하이퍼 스레딩) 시스템에서는 좋지 않습니다.
— Peter Cordes

.... 그러나 메모리 계산되어 매우 결함. 최신 CPU는 메모리 병렬 처리가 많기 때문에 DRAM 대기 시간 이 200-400 코어 클럭주기 및 L3> 40과 같지만 대역폭 은 ~ 8 ​​바이트 / 클럭입니다. (놀랍게도 L3 또는 DRAM 에 대한 단일 스레드 대역폭은 쿼드 코어 메모리 대 쿼드 코어 데스크톱이있는 많은 코어 Xeon에서 한 코어가 비행 중에 유지할 수있는 요청의 최대 동시성에 의해 제한되기 때문에 더 나쁩니다 . max_concurrency / 대기 시간 : 단일 스레드 메모리 처리량에서 Skylake가 Broadwell-E보다 훨씬 우수한 이유는 무엇입니까? )
— Peter Cordes

... 쿼드 코어와 18 코어를 비교 한 Haswell 숫자 는 7-cpu.com/cpu/Haswell.html 도 참조하십시오 . 어쨌든, 현대 CPU는 메모리를 기다리지 않으면 시계 당 엄청난 양의 작업을 수행 할 수 있습니다. 1993 년의 펜티엄이나 현대적인 저가형 듀얼 이슈 ARM과 같이 시계 당 2 개의 ALU 연산 만있는 것으로 보입니다. Ryzen 또는 스웰은 잠재적으로 4 스칼라 정수 ALU 본부 + 2 개 메모리 작전 수행 코어 당 클럭 당, 또는 훨씬 더 SIMD로한다. 예를 들어 Skylake-AVX512는 vpaddd zmm명령 당 16 개의 32 비트 요소 에서 (코어 당) 클럭 당 2 개의 처리량을 갖습니다 .
— 피터 코 데스

7

"모든 것이 파일"인 것 외에도 대부분의 다른 답변이 기반으로하는 모든 곳에서 사용의 용이성 외에도 @ user5626466이 언급 한 것처럼 성능 문제가 있습니다.

실제로 보여주기 위해 다음과 같은 간단한 프로그램을 만듭니다 nullread.c.

#include <unistd.h>
char buf[1024*1024];
int main() {
        while (read(0, buf, sizeof(buf)) > 0);
}

와 그것을 컴파일 gcc -O2 -Wall -W nullread.c -o nullread

(참고 : 파이프에서는 lseek (2)를 사용할 수 없으므로 파이프를 비우는 방법은 파이프가 비워 질 때까지 파이프를 읽는 것입니다.)

% time dd if=/dev/zero bs=1M count=5000 |  ./nullread
5242880000 bytes (5,2 GB, 4,9 GiB) copied, 9,33127 s, 562 MB/s
dd if=/dev/zero bs=1M count=5000  0,06s user 5,66s system 61% cpu 9,340 total
./nullread  0,02s user 3,90s system 41% cpu 9,337 total

반면 표준 /dev/null파일 리디렉션을 사용하면 컨텍스트 전환이 적고 커널이 데이터를 복사하는 대신 데이터를 무시하는 등의 사실로 인해 속도가 훨씬 빨라집니다.

% time dd if=/dev/zero bs=1M count=5000 > /dev/null
5242880000 bytes (5,2 GB, 4,9 GiB) copied, 1,08947 s, 4,8 GB/s
dd if=/dev/zero bs=1M count=5000 > /dev/null  0,01s user 1,08s system 99% cpu 1,094 total

(이것은 의견이 있어야하지만 너무 커서 너무 읽을 수 없습니다)


어떤 하드웨어를 테스트 했습니까? 4.8GB / s는 Skylake i7-6700k (DDR4-2666)에서 얻을 수있는 23GB / s에 비해 상당히 낮지 만 L3 캐시에서는 버퍼가 뜨겁게 유지되므로 스펙터를 사용하면 시스템 호출 비용이 비쌉니다. + 멜트 다운 완화 지원 파이프 버퍼가 1M보다 작기 때문에 배관에 이중 문제가 발생하여 쓰기 / 읽기 시스템 호출이 더 많지만 예상보다 10 배에 가까운 성능 차이가 나쁘지만 스카이 레이크 시스템의 경우 23GB / s와 비교합니다. x86-64 Linux 4.15.8-1-ARCH를 실행하는 3.3GB / s 이므로 6.8 배입니다. 이제 시스템 호출 비용 이 많이 듭니다 )
— Peter Cordes

1
64K 파이프 버퍼를 갖춘 @PeterCordes 3GB / s는 초당 2x 103124 syscalls를 제안합니다. 초당 200000 개의 syscall이있는 서버 CPU에서는 작업 세트가 거의 없기 때문에 PTI에서 ~ 8 %의 오버 헤드를 예상 할 수 있습니다. (내가 참조하는 그래프에는 PCID 최적화가 포함되어 있지 않지만 소규모 작업 세트에는 그다지 중요하지 않습니다). PTI에 큰 영향이 있는지 잘 모르겠습니다. brendangregg.com/blog/2018-02-09/…
— sourcejedi

1
흥미 롭습니다. 2MB의 L2 캐시를 가진 Silvermont 이므로 dd버퍼 + 수신 버퍼가 맞지 않습니다. 아마도 마지막 레벨 캐시 대역폭 대신 메모리 대역폭을 다루고있을 것입니다. 512k 버퍼 또는 64k 버퍼로 더 나은 대역폭을 얻을 수 있습니다. (에 따르면 strace내 바탕 화면에, write그리고 read1048576을 반환하는, 그래서 그 우리는 사용자가 지불하는 의미한다고 생각 <->., 64K 당하지, 한 번 MiB 크기 당 TLB 무효화 + 브랜치 예측의 커널 비용 플러시 @sourcejedi을 그것은 유령이다 비용이 가장 많이 드는 완화책이라고 생각합니다)
— Peter Cordes

1
@sourcejedi : 유령 완화이 활성화하는 비용 syscall바로와 반환 ENOSYS유령 완화와 스카이 레이크에 ~ 1800 사이클은 대부분되는 활성화 wrmsrBPU를 무효화하는, BeeOnRope의 테스트 @를 따라 . 완화가 비활성화 된 경우 사용자-> 커널-> 사용자 왕복 시간은 ~ 160 사이클입니다. 당신은하지만 있는 메모리의 감동을 많이, 붕괴 완화도 중요하다. Hugepages가 도움이 될 것입니다 (더 적은 TLB 항목을 다시로드해야 함).
— Peter Cordes

1
@PeterCordes 단일 코어 유닉스 시스템에서는 64K 당 1 개의 컨텍스트 스위치 또는 파이프 버퍼가 무엇이든간에 분명히 상처를 입을 것입니다 ... 실제로 [2 개의 CPU 코어를 가진 동일한 수의 컨텍스트 스위치] ( unix.stackexchange.com/questions/439260/… ); 또한 각 64k에 대한 절전 / 깨우기주기를 컨텍스트 스위치 (공칭 "유휴 프로세스"로)로 계산해야합니다. 동일한 CPU에서 파이프 라인 프로세스를 유지하면 실제로 두 배 이상 빠르게 작동했습니다.
— sourcejedi

6

귀하의 질문은 파일 대신 null 프로그램을 사용하여 간단하게 얻을 수있는 것처럼 보입니다. 아마도 우리는 "매직 파일"이라는 개념을 제거하고 대신 "일반 파이프"를 가질 수 있습니다.

그러나 파이프도 파일이라는 것을 고려 하십시오 . 일반적으로 이름이 지정되지 않았으므로 파일 디스크립터를 통해서만 조작 할 수 있습니다.

이 다소 고안된 예를 고려하십시오.

$ echo -e 'foo\nbar\nbaz' | grep foo
foo

Bash의 프로세스 대체를 사용하면 더 둥근 길을 통해 동일한 것을 달성 할 수 있습니다.

$ grep foo <(echo -e 'foo\nbar\nbaz')
foo

을 바꾸기 grep위해 echo우리는 내부적으로 볼 수 있습니다 :

$ echo foo <(echo -e 'foo\nbar\nbaz')
foo /dev/fd/63

<(...)구조는 단지 파일 이름으로 대체하고, GREP은 오래된 파일을 여는, 그냥 익명을 어떻게 생각됩니다 /dev/fd/63. 여기, /dev/fd파일이 액세스하는 모든 파일 설명자에 대해 명명 된 파이프를 만드는 매직 디렉토리입니다.

일반 파일과 같이 모든 것이 mkfifo표시되는 명명 된 파이프를 만드는 것이 마술을 덜 만들 수 ls있습니다.

$ mkfifo foofifo
$ ls -l foofifo 
prw-rw-r-- 1 indigo indigo 0 Apr 19 22:01 foofifo
$ grep foo foofifo

다른 곳 :

$ echo -e 'foo\nbar\nbaz' > foofifo

보라, grep이 출력 할 것이다 foo.

파이프와 일반 파일을 인식하고 / dev / null과 같은 특수 파일이 모두 파일 일 뿐이라고 생각하면 null 프로그램을 구현하는 것이 더 복잡합니다. 커널은 파일에 대한 쓰기를 어느 쪽이든 처리해야하지만 / dev / null의 경우 쓰기를 바닥에 떨어 뜨릴 수 있지만 파이프를 사용하면 실제로 바이트를 다른 프로그램으로 전송해야합니다. 실제로 읽어보십시오.


@Lyle 그래? 그렇다면 왜 에코가 인쇄 /dev/fd/63됩니까?
— Phil Frost

흠. 좋은 지적. 글쎄, 이것은 쉘로 구현되었으므로 아마도 당신의 쉘은 내가 자란 이전 Bourne 쉘과 다를 수 있습니다.
— Lyle

한 가지 차이점은 echo는 stdin에서 읽지 않지만 grep은 읽지 만 쉘이 실행하기 전에 어떻게 알 수 있는지 생각할 수 없습니다.
— Lyle

1
그리고 strace는 이것을 명확하게 만듭니다. bash를 사용하면 정확히 맞습니다. '<(...)'구문은 <filename과는 상당히 다른 일을하고 있습니다. 흠. 나는 무언가를 배웠다.
— Lyle

0

역사적인 패러다임과 성능을 넘어서는 보안 문제가 있다고 주장합니다. 권한이있는 실행 자격 증명이있는 프로그램 수를 제한하는 것은 아무리 간단하더라도 시스템 보안의 기본 원칙입니다. /dev/null시스템 서비스에서 사용하기 때문에 그러한 특권을 가지려면 반드시 교체 해야합니다. 최신 보안 프레임 워크는 악용을 방지하는 훌륭한 작업을 수행하지만 절대 안전하지는 않습니다. 파일로 액세스 한 커널 구동 장치는 훨씬 더 악용하기가 어렵습니다.


말도 안되는 소리. 버그가없는 커널 드라이버를 작성하는 것은 stdin을 읽고 버리는 버그가없는 프로그램을 작성하는 것보다 쉽지 않습니다. 그것은 모두 그래서,이 setuid 또는 아무것도 할 필요가 없습니다 /dev/null또는 제안 된 입력 폐기 프로그램, 공격 벡터가 같은 것 : 이상한 뭔가를 루트로 실행되는 스크립트 또는 프로그램을 얻을 (같은 시도 lseek에 /dev/null또는 오픈 동일한 프로세스에서 여러 번 또는 IDK 또는 /bin/null이상한 환경으로 호출하십시오 .
— Peter Cordes

0

다른 사람이 이미 지적했듯이, /dev/null 인 코드 라인의 소수 만든 프로그램. 이 코드 줄은 커널의 일부입니다.

보다 명확하게하기 위해 Linux 구현은 다음과 같습니다. 문자 장치는 읽거나 쓸 때 함수를 호출합니다. 에 쓰기 /dev/null통화 write_null 읽기 호출 동안, read_null 등록 여기 .

말 그대로 몇 줄의 코드 :이 함수는 아무것도하지 않습니다. 읽고 쓰는 것 이외의 기능을 세는 경우에만 손의 손가락보다 더 많은 코드 줄이 필요합니다.


어쩌면 내가 더 정확하게 말했을 것입니다. 프로그램 대신 char 장치로 구현하는 이유를 의미했습니다. 어느 쪽이든 몇 줄이지 만 프로그램 구현은 훨씬 간단합니다. 다른 답변이 지적했듯이 이것에는 꽤 많은 이점이 있습니다. 그들 중 효율성과 휴대 성 최고.
— Ankur S

확실한. 실제 구현이 재미 있었기 때문에이 답변을 추가했습니다 (최근에 스스로 발견했습니다). 그러나 진짜 이유는 다른 사람들이 실제로 지적한 것입니다.
— Matthieu Moy

나도! 나는 최근에 리눅스에서 장치를 배우기 시작했고 대답은 상당히 유익했다
— Ankur S

-2

/ dev / chargen / dev / zero와 / dev / null을 포함한 다른 사람들도 알고 있기를 바랍니다.

LINUX / UNIX는이 중 몇 가지를 제공하므로 사람들이 WELL WRITTEN CODE FRAGMEnTS를 잘 활용할 수 있습니다.

Chargen은 특정하고 반복되는 문자 패턴을 생성하도록 설계되었습니다. 속도가 매우 빠르며 직렬 장치의 한계를 뛰어 넘고 테스트 또는 기타 테스트에 실패하거나 실패한 직렬 프로토콜을 디버깅하는 데 도움이됩니다.

Zero는 기존 파일을 채우거나 많은 0을 출력하도록 설계되었습니다.

/ dev / null은 같은 생각을 가진 또 다른 도구 일뿐입니다.

툴킷에있는 이러한 모든 도구는 기존 프로그램이 장치 또는 파일 교체와 같은 특정 요구 사항에 관계없이 고유 한 작업을 수행 할 수있는 기회가 절반임을 의미합니다.

LINUX 버전의 문자 장치 몇 개만 제공하면 누가 가장 흥미로운 결과를 낼 수 있는지 공모를 설정할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.