Eu suspeito que o porquê tenha muito a ver com a visão / design que moldou o Unix (e consequentemente o Linux), e as vantagens decorrentes dele.
Sem dúvida, há um benefício de desempenho não desprezível para não criar um processo extra, mas acho que há mais: o Early Unix tinha uma metáfora "tudo é um arquivo", que tem uma vantagem não óbvia, mas elegante. você olha para isso de uma perspectiva de sistema, ao invés de uma perspectiva de script de shell.
Digamos que você tenha seu programa de linha de comando null
e /dev/null
do nó do dispositivo. A partir de uma perspectiva de script de shell, o programa foo | null
é realmente útil e conveniente , e foo >/dev/null
demora um pouco mais para ser digitado e pode parecer estranho. / p>
Mas aqui estão dois exercícios:
-
Vamos implementar o programa null
usando as ferramentas existentes do Unix e /dev/null
- easy: cat >/dev/null
. Feito.
-
Você pode implementar /dev/null
em termos de null
?
Você está absolutamente certo de que o código C apenas para descartar a entrada é trivial, então talvez ainda não seja óbvio porque é útil ter um arquivo virtual disponível para a tarefa.
Considere: quase toda linguagem de programação já precisa trabalhar com arquivos, descritores de arquivo e caminhos de arquivo, porque eles faziam parte do paradigma "tudo é um arquivo" do Unix desde o começo.
Se tudo que você tem são programas que escrevem para stdout, bem, o programa não se importa se você os redireciona para um arquivo virtual que engula todas as gravações, ou um pipe para um programa que engula todas as gravações.
Agora, se você tiver programas que usam caminhos de arquivo para ler ou gravar dados (o que a maioria dos programas faz) - e você deseja adicionar a funcionalidade "entrada em branco" ou "descartar esta saída" a esses programas - bem, com /dev/null
que vem de graça.
Observe que a elegância é a de reduzir a complexidade do código de todos os programas envolvidos - para cada usecase comum, mas especial, que seu sistema pode fornecer como um "arquivo" com um "nome de arquivo" real, seu código pode evitar adicionando opções de linha de comando personalizadas e caminhos de código personalizados para manipular.
A boa engenharia de software geralmente depende de encontrar metáforas boas ou "naturais" para abstrair algum elemento de um problema de uma forma que se torne mais fácil de pensar mas permaneça flexível , para que você possa resolver basicamente a mesma gama de problemas de alto nível sem ter que gastar tempo e energia mental na reimplementação de soluções para os mesmos problemas de nível mais baixo constantemente.
"Tudo é um arquivo" parece ser uma dessas metáforas para acessar recursos: você chama open
de um determinado caminho em um namespace heirárquico, obtendo uma referência (descritor de arquivo) para o objeto e você pode read
e write
, etc nos descritores de arquivos. Seu stdin / stdout / stderr também são descritores de arquivos que acabaram de ser pré-abertos para você. Seus canais são apenas arquivos e descritores de arquivos, e o redirecionamento de arquivos permite que você cole todas essas partes juntas.
O Unix teve sucesso tanto quanto em parte devido ao bom desempenho dessas abstrações, e /dev/null
é melhor entendido como parte desse todo.
P.S. Vale a pena olhar para a versão Unix de "tudo é um arquivo" e coisas como /dev/null
como os primeiros passos para uma generalização mais flexível e poderosa da metáfora que foi implementada em muitos sistemas que se seguiram.
Por exemplo, no Unix, objetos especiais como /dev/null
tiveram que ser implementados no próprio kernel, mas é útil o suficiente para expor a funcionalidade na forma de arquivo / pasta que, desde então, vários sistemas foram criados. que fornecem uma maneira de os programas fazerem isso.
Um dos primeiros foi o sistema operacional Plan 9, feito por algumas das mesmas pessoas que fizeram o Unix. Mais tarde, o GNU Hurd fez algo similar com seus "tradutores". Enquanto isso, o Linux acabou ficando FUSE (que se espalhou para os outros sistemas mainstream até agora).