Por que o $ ls > ls.out
'ls.out' é incluído na lista de nomes de arquivos no diretório atual? Por que isso foi escolhido? Por que não o contrário?
command-line
bash
redirect
Edward Torvalds
fonte
fonte
ls > ../ls.out
Respostas:
Ao avaliar o comando, o
>
redirecionamento é resolvido primeiro: pelo tempo quels
o arquivo de saída já foi criado.Esse também é o motivo pelo qual a leitura e gravação no mesmo arquivo usando um
>
redirecionamento dentro do mesmo comando trunca o arquivo; no momento em que o comando é executado, o arquivo já está truncado:Truques para evitar isso:
<<<"$(ls)" > ls.out
(funciona para qualquer comando que precise ser executado antes que o redirecionamento seja resolvido)A substituição do comando é executada antes de o comando externo ser avaliado, e
ls
é executada antes dals.out
criação:ls | sponge ls.out
(funciona para qualquer comando que precise ser executado antes que o redirecionamento seja resolvido)sponge
grava no arquivo somente quando o restante do canal terminar de executar, portanto,ls
é executado antes dals.out
criação (sponge
é fornecido com omoreutils
pacote):ls * > ls.out
(funciona parals > ls.out
o caso específico)A expansão do nome do arquivo é realizada antes que o redirecionamento seja resolvido, portanto,
ls
será executado em seus argumentos, que não conterãols.out
:Por que os redirecionamentos são resolvidos antes da execução do programa / script / o que quer que seja, não vejo um motivo específico pelo qual é obrigatório fazê-lo, mas vejo dois motivos pelos quais é melhor fazê-lo:
não redirecionar o STDIN antecipadamente tornaria o programa / script / o que quer que seja mantido até que o STDIN seja redirecionado;
não redirecionar o STDOUT de antemão deve necessariamente fazer com que o shell armazene a saída do programa / script / o que quer que seja até o redirecionamento do STDOUT;
Portanto, uma perda de tempo no primeiro caso e uma perda de tempo e memória no segundo caso.
É exatamente isso que me ocorre, não estou afirmando que essas são as razões reais; mas acho que, no fim das contas, se alguém tivesse uma escolha, eles iriam redirecionar antes pelas razões acima mencionadas.
fonte
De
man bash
:A primeira frase sugere que a saída é feita para ir para outro lugar que não seja o
stdin
redirecionamento, antes do comando ser executado. Portanto, para ser redirecionado para o arquivo, o arquivo deve primeiro ser criado pelo próprio shell.Para evitar um arquivo, sugiro que você redirecione a saída para o pipe nomeado primeiro e depois para o arquivo. Observe o uso de
&
para retornar o controle do terminal ao usuárioMas por que?
Pense sobre isso - onde será a saída? Um programa tem funções como
printf
,sprintf
,puts
, que todos pelo movimento padrão parastdout
, mas a sua saída pode ser ido para arquivo se o arquivo não existe, em primeiro lugar? É como a água. Você pode pegar um copo de água sem colocar o copo embaixo da torneira primeiro?fonte
Não discordo das respostas atuais. O arquivo de saída deve ser aberto antes da execução do comando ou o comando não terá nenhum lugar para gravar sua saída.
Isso ocorre porque "tudo é um arquivo" em nosso mundo. A saída para a tela é SDOUT (também conhecido como descritor de arquivo 1). Para um aplicativo gravar no terminal, ele abre o fd1 e grava nele como um arquivo.
Quando você redireciona a saída de um aplicativo em um shell, está alterando o fd1 para que ele aponte para o arquivo. Quando você canaliza, altera o STDOUT de um aplicativo para se tornar o STDIN de outro (fd0).
Mas é legal dizer isso, mas você pode facilmente ver como isso funciona
strace
. É um material bastante pesado, mas este exemplo é bastante curto.Dentro
strace.out
, podemos ver os seguintes destaques:Isso abre
ls.out
comofd3
. Escreva apenas. Trunca (substitui) se existir, caso contrário, cria.Isso é um pouco de malabarismo. Desviamos STDOUT (fd1) para fd10 e o fechamos. Isso ocorre porque não estamos produzindo nada para o STDOUT real com este comando. Ele termina duplicando a alça de gravação
ls.out
e fechando a alça original.É isso que procura pelo executável. Uma lição talvez para não ter um longo caminho;)
Em seguida, o comando é executado e o pai espera. Durante esta operação, qualquer STDOUT realmente será mapeado para o identificador de arquivo aberto
ls.out
. Quando o filho emiteSIGCHLD
, isso informa ao processo pai que está concluído e que pode ser retomado. Ele termina com um pouco mais de malabarismo e finalizaçãols.out
.Por que há tão muito malabarismo? Não, também não tenho certeza.
Claro que você pode mudar esse comportamento. Você pode armazenar em buffer a memória com algo parecido
sponge
e isso será invisível a partir do comando proceder. Ainda estamos afetando os descritores de arquivo, mas não de uma maneira visível no sistema de arquivos.fonte
Também há um bom artigo sobre Implementação de operadores de redirecionamento e canal no shell . O que mostra como o redirecionamento pode ser implementado para que
$ ls > ls.out
possa parecer:fonte