AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 438130
Accepted
Ankur S
Ankur S
Asked: 2018-04-17 07:28:04 +0800 CST2018-04-17 07:28:04 +0800 CST 2018-04-17 07:28:04 +0800 CST

Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples?

  • 772

Estou tentando entender o conceito de arquivos especiais no Linux. No entanto, ter um arquivo especial /devparece bobo quando sua função pode ser implementada por um punhado de linhas em C, pelo que sei.

Além disso, você pode usá-lo praticamente da mesma maneira, ou seja, canalizando em nullvez de redirecionar para /dev/null. Existe uma razão específica para tê-lo como um arquivo? Torná-lo um arquivo não causa muitos outros problemas, como muitos programas acessando o mesmo arquivo?

files devices
  • 9 9 respostas
  • 24599 Views

9 respostas

  • Voted
  1. Best Answer
    ioctl
    2018-04-17T12:55:58+08:002018-04-17T12:55:58+08:00

    Além dos benefícios de desempenho do uso de um dispositivo especial de personagem, o principal benefício é a modularidade . /dev/null pode ser usado em quase qualquer contexto em que um arquivo é esperado, não apenas em pipelines de shell. Considere programas que aceitam arquivos como parâmetros de linha de comando.

    # 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
    

    Esses são todos os casos em que usar um programa como fonte ou coletor seria extremamente complicado. Mesmo no caso do shell pipeline, stdout e stderr podem ser redirecionados para arquivos de forma independente, algo que é difícil de fazer com executáveis ​​como coletores:

    # Suppress errors, but print output.
    $ grep foo * 2>/dev/null
    
    • 156
  2. DopeGhoti
    2018-04-17T07:56:28+08:002018-04-17T07:56:28+08:00

    Para ser justo, não é um arquivo regular em si; é um dispositivo especial de personagem :

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

    Funcionar como um dispositivo e não como um arquivo ou programa significa que é uma operação mais simples redirecionar a entrada ou a saída dele, pois pode ser anexado a qualquer descritor de arquivo, incluindo entrada/saída/erro padrão.

    • 62
  3. mtraceur
    2018-04-17T14:05:18+08:002018-04-17T14:05:18+08:00

    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 em não ativar um processo extra, mas acho que há mais: o Unix antigo tinha uma metáfora "tudo é um arquivo", que tem uma vantagem não óbvia, mas elegante se você olhar para de uma perspectiva de sistema, em vez de uma perspectiva de script de shell.

    Digamos que você tenha seu nullprograma de linha de comando e /dev/nullo nó do dispositivo. Do ponto de vista do shell script, o foo | nullprograma é realmente genuinamente útil e conveniente , e foo >/dev/nullleva um pouco mais de tempo para digitar e pode parecer estranho.

    Mas aqui estão dois exercícios:

    1. Vamos implementar o programa nullusando as ferramentas existentes do Unix e /dev/null- fácil: cat >/dev/null. Feito.

    2. Você pode implementar /dev/nullem termos de null?

    Você está absolutamente certo de que o código C para apenas descartar a entrada é trivial, então pode não ser óbvio por que é ú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 início.

    Se tudo o que você tem são programas que gravam em stdout, bem, o programa não se importa se você os redireciona para um arquivo virtual que engole todas as gravações ou um canal para um programa que engole todas as gravações.

    Agora, se você tiver programas que usam caminhos de arquivo para leitura ou gravação de dados (o que a maioria dos programas faz) - e deseja adicionar a funcionalidade "entrada em branco" ou "descartar esta saída" a esses programas - bem, com /dev/nullisso vem de graça.

    Observe que a elegância disso reduz a complexidade do código de todos os programas envolvidos - para cada caso de uso comum, mas especial, que seu sistema pode fornecer como um "arquivo" com um "nome de arquivo" real, seu código pode evitar a adição de comando personalizado -line opções 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 maneira que se torne mais fácil de pensar , mas permaneça flexível , de modo que você possa resolver basicamente a mesma gama de problemas de nível superior sem ter que gaste tempo e energia mental reimplementando constantemente soluções para os mesmos problemas de nível inferior.

    "Tudo é um arquivo" parece ser uma dessas metáforas para acessar recursos: você chama openum determinado caminho em um namespace hierárquico, obtendo uma referência (descritor de arquivo) para o objeto, e você pode reade write, etc nos descritores de arquivo. Seu stdin/stdout/stderr também são descritores de arquivo que foram pré-abertos para você. Seus pipes são apenas arquivos e descritores de arquivo, e o redirecionamento de arquivo permite que você junte todas essas peças.

    O Unix teve tanto sucesso quanto em parte por causa de quão bem essas abstrações funcionaram juntas e /dev/nullé melhor compreendida como parte desse todo.


    PS Vale a pena olhar para a versão Unix de "tudo é um arquivo" e coisas como /dev/nullos 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 semelhantes a arquivos como /dev/nulltiveram que ser implementados no próprio kernel, mas é útil o suficiente para expor a funcionalidade no formato de arquivo/pasta que, desde então, vários sistemas foram criados para fornecer uma maneira para os programas fazer isso.

    Um dos primeiros foi o sistema operacional Plan 9, feito por algumas das mesmas pessoas que criaram o Unix. Mais tarde, o GNU Hurd fez algo semelhante com seus "tradutores". Enquanto isso, o Linux acabou recebendo o FUSE (que se espalhou para os outros sistemas convencionais também).

    • 55
  4. user5626466
    2018-04-17T08:21:44+08:002018-04-17T08:21:44+08:00

    Acho que /dev/nullé um dispositivo de caractere (que se comporta como um arquivo comum) em vez de um programa por motivos de desempenho .

    Se fosse um programa, seria necessário carregar, iniciar, agendar, executar e depois parar e descarregar o programa. É claro que o programa C simples que você está descrevendo não consumiria muitos recursos, mas acho que faz uma diferença significativa ao considerar um grande número (digamos milhões) de ações de redirecionamento / canalização, pois as operações de gerenciamento de processos são caras em grande escala, pois eles envolvem trocas de contexto.

    Outra suposição: canalizar para um programa requer que a memória seja alocada pelo programa receptor (mesmo que seja descartada logo em seguida). Portanto, se você canalizar a ferramenta, terá o dobro do consumo de memória, uma vez no programa de envio e novamente no programa de recebimento.

    • 14
  5. Matija Nalis
    2018-04-20T03:32:10+08:002018-04-20T03:32:10+08:00

    Além de "tudo é um arquivo" e, portanto, facilidade de uso em todos os lugares em que a maioria das outras respostas se baseia, também há problemas de desempenho, como @ user5626466 menciona.

    Para mostrar na prática, vamos criar um programa simples chamado nullread.c:

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

    e compilá-lo comgcc -O2 -Wall -W nullread.c -o nullread

    (Nota: não podemos usar lseek(2) em pipes, então a única maneira de drenar o pipe é ler dele até que esteja vazio).

    % 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
    

    considerando que com o redirecionamento de arquivo padrão /dev/nullobtemos velocidades muito melhores (devido aos fatos mencionados: menos troca de contexto, kernel apenas ignorando os dados em vez de copiá-los, etc.):

    % 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
    

    (isso deveria ser um comentário lá, mas é muito grande para isso e seria completamente ilegível)

    • 7
  6. Phil Frost
    2018-04-20T14:07:47+08:002018-04-20T14:07:47+08:00

    Sua pergunta é feita como se algo fosse ganho talvez em simplicidade usando um programa nulo em vez de um arquivo. Talvez possamos nos livrar da noção de "arquivos mágicos" e, em vez disso, ter apenas "tubos comuns".

    Mas considere, um pipe também é um arquivo . Eles normalmente não são nomeados e, portanto, só podem ser manipulados por meio de seus descritores de arquivo.

    Considere este exemplo um tanto artificial:

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

    Usando a substituição de processo do Bash, podemos realizar a mesma coisa de uma maneira mais indireta:

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

    Substitua o grepfor echoe podemos ver embaixo das cobertas:

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

    A <(...)construção é apenas substituída por um nome de arquivo e o grep pensa que está abrindo qualquer arquivo antigo, apenas por acaso é nomeado /dev/fd/63. Aqui /dev/fdestá um diretório mágico que cria canais nomeados para cada descritor de arquivo possuído pelo arquivo que o acessa.

    Poderíamos torná-lo menos mágico mkfifopara fazer um pipe nomeado que aparece lse tudo, como um arquivo comum:

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

    Em outro lugar:

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

    e eis que o grep produzirá foo.

    Eu acho que uma vez que você percebe que pipes e arquivos regulares e arquivos especiais como /dev/null são apenas arquivos, é aparente que a implementação de um programa nulo é mais complexa. O kernel tem que lidar com gravações em um arquivo de qualquer maneira, mas no caso de /dev/null ele pode simplesmente descartar as gravações no chão, enquanto com um pipe ele tem que transferir os bytes para outro programa, que então tem que realmente lê-los.

    • 6
  7. NickW
    2018-04-21T08:13:01+08:002018-04-21T08:13:01+08:00

    Eu diria que há uma questão de segurança além dos paradigmas históricos e do desempenho. Limitar o número de programas com credenciais de execução privilegiadas, não importa o quão simples seja, é um princípio fundamental da segurança do sistema. /dev/nullCertamente seria necessário um substituto para ter tais privilégios devido ao uso pelos serviços do sistema. Estruturas de segurança modernas fazem um excelente trabalho na prevenção de exploits, mas não são infalíveis. Um dispositivo controlado pelo kernel acessado como um arquivo é muito mais difícil de explorar.

    • 0
  8. Matthieu Moy
    2018-04-24T07:14:08+08:002018-04-24T07:14:08+08:00

    Como outros já apontaram, /dev/null é um programa feito de um punhado de linhas de código. É que essas linhas de código fazem parte do kernel.

    Para deixar mais claro, aqui está a implementação do Linux: um dispositivo de caractere chama funções quando é lido ou gravado. Escrever para /dev/nullchamadas write_null , enquanto lê chamadas read_null , registrado aqui .

    Literalmente um punhado de linhas de código: essas funções não fazem nada. Você precisaria de mais linhas de código do que dedos em suas mãos apenas se contasse outras funções além de ler e escrever.

    • 0
  9. helpful
    2018-04-21T05:45:25+08:002018-04-21T05:45:25+08:00

    Espero que você também esteja ciente do /dev/chargen /dev/zero e outros como eles, incluindo /dev/null.

    O LINUX/UNIX tem alguns deles - disponibilizados para que as pessoas possam fazer bom uso de FRAGMENTOS DE CÓDIGO BEM ESCRITO.

    Chargen é projetado para gerar um padrão específico e repetitivo de caracteres - é bastante rápido e ultrapassaria os limites dos dispositivos seriais e ajudaria a depurar protocolos seriais que foram escritos e falharam em algum teste ou outro.

    Zero é projetado para preencher um arquivo existente ou produzir um monte de zeros

    /dev/null é apenas outra ferramenta com a mesma ideia em mente.

    Todas essas ferramentas em seu kit de ferramentas significam que você tem meia chance de fazer um programa existente fazer algo único sem levar em conta (sua necessidade específica) como dispositivos ou substituições de arquivos

    Vamos criar um concurso para ver quem consegue produzir o resultado mais emocionante, considerando apenas os poucos dispositivos de personagem em sua versão do LINUX.

    • -2

relate perguntas

  • Remova arquivos com os menores sufixos de nome de arquivo

  • Listar arquivos classificados de acordo com a linha de conteúdo específica

  • Como saber antecipadamente se um .zip tem um diretório pai dentro

  • Como encontrar tipos de arquivos específicos e tar-los?

  • du/df e ls relatando diferentes usos de disco

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Como exportar uma chave privada GPG e uma chave pública para um arquivo

    • 4 respostas
  • Marko Smith

    ssh Não é possível negociar: "nenhuma cifra correspondente encontrada", está rejeitando o cbc

    • 4 respostas
  • Marko Smith

    Como podemos executar um comando armazenado em uma variável?

    • 5 respostas
  • Marko Smith

    Como configurar o systemd-resolved e o systemd-networkd para usar o servidor DNS local para resolver domínios locais e o servidor DNS remoto para domínios remotos?

    • 3 respostas
  • Marko Smith

    Como descarregar o módulo do kernel 'nvidia-drm'?

    • 13 respostas
  • Marko Smith

    apt-get update error no Kali Linux após a atualização do dist [duplicado]

    • 2 respostas
  • Marko Smith

    Como ver as últimas linhas x do log de serviço systemctl

    • 5 respostas
  • Marko Smith

    Nano - pule para o final do arquivo

    • 8 respostas
  • Marko Smith

    erro grub: você precisa carregar o kernel primeiro

    • 4 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Martin Hope
    rocky Como exportar uma chave privada GPG e uma chave pública para um arquivo 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Wong Jia Hau ssh-add retorna com: "Erro ao conectar ao agente: nenhum arquivo ou diretório" 2018-08-24 23:28:13 +0800 CST
  • Martin Hope
    Evan Carroll status systemctl mostra: "Estado: degradado" 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim Como podemos executar um comando armazenado em uma variável? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 Como ver as últimas linhas x do log de serviço systemctl 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - pule para o final do arquivo 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla Por que verdadeiro e falso são tão grandes? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST
  • Martin Hope
    Bagas Sanjaya Por que o Linux usa LF como caractere de nova linha? 2017-12-20 05:48:21 +0800 CST

Hot tag

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve