ls
produzirá o que deve ser produzido em sua saída padrão . Para fazer isso, ele chama a chamada do sistema write
, algo como:
write(1, "file1 file2...\n", 16)
(ou, mais provavelmente, chama libc
funções como printf
ou fwrite
que eventualmente fazem a chamada do sistema write()
)
Ele assume que o descritor de arquivo 1
(stdout por convenção) já estava aberto e aponta para algo. Na verdade, ls
verifica se o descritor de arquivo 1 aponta para um terminal ou outra coisa. Se não apontar para um terminal, ele será exibido:
write(1, "file1\nfile2...\n", 15)
Ou seja, ele grava um arquivo por linha quando a saída não vai para um terminal.
Quando você escreve:
ls file1 file2
O descritor de arquivo 1 de
ls
apontará para o mesmo recurso que o fd 1 do shell (assim, por exemplo, se foi um shell interativo iniciado por xterm
, que apontará para o dispositivo pseudo-terminal controlado por xterm). O shell não faz nada de especial, ele é herdado em fork
e, como o sinalizador O_CLOEXEC
normalmente não está definido no descritor de arquivo, ele é preservado em execve
.
Se você escrever:
var=$(ls file1 file2)
O shell cria um pipe e atribui o fd 1 do processo filho à extremidade de gravação desse pipe e lê o outro extremo do pipe para preencher a variável var
.
Não é feito magicamente após a saída, é apenas feito como parte do trabalho do processo. É independente de qualquer outra atividade do shell. ls
é apenas outro processo com seu fd
1 conectado a algum recurso como o terminal, enquanto o shell é outro processo ocupado fazendo um waitpid()
.
O que você pode achar é que quando o stdout não é um terminal, ls
armazena sua saída e só chamaria write()
quando dados suficientes (o suficiente sendo vários kilobytes) foram acumulados ou estão fechando sua saída ou estão saindo . Assim, a esse respeito, você encontrará o write
concluído ao sair, mas apenas como parte do flushing
dos buffers que estão sendo feitos por essas bibliotecas de E / S.