Quando o comando cat
está em execução, o terminal está no modo de entrada canônica . Isto significa, em resumo, que a disciplina de linha do terminal está lidando com edição de linha, e está respondendo a todos os caracteres especiais configurados para o terminal (visível e configurável com o% comandostty
).
O comando cat
é simplesmente read()
ing de sua entrada padrão até que uma chamada read()
retorne zero bytes lidos, a convenção POSIX para atingir o final do arquivo.
Os terminais não têm realmente um "fim". Mas há uma circunstância em que read()
de um dispositivo terminal retorna zero bytes. Quando a disciplina de linha recebe o caractere especial "EOF", seja lá o que for que esteja configurado no momento, isso fará com que read()
retorne com o que estiver no buffer de edição nesse ponto. Se o buffer de edição estiver vazio, isso retorna zero bytes lidos de read()
, fazendo com que cat
seja encerrado.
cat
também sai em resposta a sinais cujas ações padrão são para finalizar o processo. A disciplina de linha também gera sinais em resposta a caracteres especiais. Os caracteres especiais "INTR" e "QUIT" fazem com que os sinais INT
e QUIT
sejam enviados para o processo de primeiro plano (grupo), que será / contém o processo cat
. A ação padrão desses sinais é finalizar o processo cat
.
O que leva às diferenças observáveis:
- Ctrl + D só tem esta ação quando é o caractere especial do EOT. Isto é geralmente o caso, mas não é necessariamente o caso. Da mesma forma, Ctrl + C só tem sua ação quando é o caractere especial INTR.
-
Ctrl + D não fará com que
cat
termine quando a linha não estiver de fato vazia no momento. Uma interrupção gerada por Ctrl + C irá, no entanto. - Uma implementação ingênua de
cat
na linguagem C bloqueará a saída padrão do buffer se ela for direcionada para um arquivo, como na pergunta. Em teoria, isso poderia levar a que as linhas em buffer e ainda não fossem perdidas secat
fosse terminado porSIGINT
.Na prática, as bibliotecas BSD e GNU C implementam um modo de buffering que não é descrito no C ou Padrões de linguagem C ++. Saída padrão quando redirecionado para arquivo ou pipe é smart buffered . É bloqueado em bloco; exceto que sempre que a biblioteca C se encontra prestes a
read()
o início de uma nova linha a partir de qualquer descritor de arquivo que esteja aberto para um dispositivo de terminal, ele libera a saída padrão. (As bibliotecas BSD e GNU C não implementam exatamente a mesma semântica e fazem mais do que isso, estritamente falando, mas esse comportamento é um subconjunto comum.) Assim, um sinal de interrupção não causará saída em buffer perdida quandocat
for construído no topo de tal biblioteca C. - Obviamente, se
cat
fizer parte de um pipeline de comando, algum outro outro processo poderia armazenar em buffer os dados, a jusante decat
, antes que esses dados alcancem um arquivo de saída. Então, novamente, quando a disciplina de linha enviaSIGINT
, que (por padrão) encerra todos os processos no pipeline, os dados de entrada armazenados em buffer e ainda não gravados serão perdidos; Considerando que terminarcat
normalmente com o caractere especial "EOF" fará com que o pipeline termine normalmente, com todos os dados passando para o processo downstream antes de ele receber uma indicação EOF de itsread()
de sua entrada padrão.
Observe que isso tem muito pouca relação com o que acontece quando o shell interativo está lendo uma linha de entrada de você. Quando o seu shell está esperando pela entrada, o terminal está no modo de entrada não-canônico , em qual modo a disciplina de linha não faz nenhum tratamento especial de caracteres especiais. Como o seu shell trata Ctrl + D e Ctrl + C é inteiramente da biblioteca de edição de entrada que o seu shell usa (libedit, readline ou ZLE) e como essa biblioteca de edição foi configurada (com associações de teclas e semelhantes).
Leitura adicional
- Interface do terminal POSIX . Wikipédia.