paulo1205
(usa Ubuntu)
Enviado em 12/11/2014 - 11:52h
daemonio escreveu:
A sintaxe do exec é:
exec descritor <|> arquivo
Na verdade, é um pouco mais do que isso.
Normalmente, quando você diz ao shell para rodar algum comando externo (sem usar
exec), ele cria um processo novo e executa o comando nesse processo novo, e fica esperando o processo novo acabar. Você pode aplicar redirecionamentos de entrada e saída sobre esses comandos, mas eles só vão valer nos processos criados pelo shell, não no processo original do próprio shell.
Uma pipeline é uma extensão da ideia acima. Cada comando que constitui a pipeline executa num processo distinto, tanto entre si quanto do processo do shell. Entre tais processos, o shell faz um tipo especial de redirecionamento, que é tal que a saída de cada comando é redirecionado para a entrada do comando seguinte na pipeline.
É possível redirecionar também alguns comandos internos do shell, tanto de/para arquivos quanto como parte de uma pipeline. No entanto, o redirecionamento vale somente para esse comando, e qualquer comando subsequente não vai ter noção da existência dos redirecionamentos dos comandos anterior. Aliás, no caso específico de pipelines, se o comando interno vier à direta do sinal de pipe (“
|”), o shell vai executar tal comando num processo filho, o que torna o caráter transitório desse redirecionamento uma necessidade, não uma escolha.
Sabendo disso, podemos voltar ao comando
exec.
O
exec serve para executar um comando externo sem criar um novo processo (i.e. o comando toma completamente o lugar do shell -- quando o comando termina, o processo termina). O
exec permite, mas não obriga, que se façam redirecionamentos de entrada e saída sobre o
processo corrente antes de executar o comando externo, de modo que o comando começa a executar com todos os redirecionamentos já aplicados.
Não é possível executar um comando interno do shell com
exec. No entanto, é possível omitir completamente a referência a qualquer comando. Esse é um caso particular de uso, em que a mesma instância do shell continua executando no mesmo processo, como se nada tivesse acontecido, exceto pelo fato de que qualquer redirecionamento aplicado pelo
exec ao processo adquire caráter permanente no próprio shell. Qualquer comando executado posteriormente, tanto interno como externo, mesmo em processos filhos, vai enxergar tais redirecionamentos.
É até possível
exemplos são:
exec 4</etc/passwd
exec 5>/tmp/arquivo_escrita
resumindo: a última parte deve ser um nome de arquivo (ou um número de descritor associado a algum arquivo)
No seu código, você utilizou a saída dos comandos como parâmetro pro exec e isso não vai dar certo.
O correto seria:
exec < <(ls)
O <(ls) cria um arquivo interno e o nome dele é passado para o exec pelo bash.
Na verdade, existe uma outra forma de “corrigir” o que ele fez.
exec 3<<< "$var$aux"
Só que eu não sei o quanto isso impacta no uso de memória.
O exec é util quando se quer ler vários arquivos com um so while loop. É necessário ser um arquivo em disco já que ele trabalha com descritores de arquivos.
Errado. Apesar da terminologia, descritores de arquivo não são necessariamente arquivos em disco. Sockets e pipes, por exemplo, são descritores de arquivos, e não são visíveis em parte alguma do sistema de arquivos. Aliás, mesmo algumas coisas visíveis no sistema de arquivos e que podem produzir descritores quando abertas com
open() são totalmente virtuais, e não residem realmente em disco (várias coisas em /dev, /proc e /sys, por exemplo).
Aliás, o exemplo que você mesmo deu quando fez “
exec < <(ls)” mostra isso: você está associando ao descritor 0 um pseudo-arquivo que é um pipe feito com a saída do comando ls.
Para juntar somente saídas de vários comandos, tem-se métodos mais simples, como esse:
$ (cmd1; cmd2; cmd3) > saida_de_todos_comandos.txt
ou por que não:
$ cmd1 > saida_de_todos_comandos.txt
$ cmd2 >> saida_de_todos_comandos.txt
$ cmd3 >> saida_de_todos_comandos.txt
depois só processar o arquivo txt em um só while loop.
A vantagem de fazer com arquivo intermediário é que você minimiza a quantidade de processos simultaneamente em execução. Isso é útil se você tiver sérias restrições de memória ou limites impostos no número de processos. Mas há motivos por que não:
- Porque pode não ser desejável -- às vezes, nem mesmo possível -- criar um arquivo temporário (disco cheio, disco read-only).
- O espaço em disco pode acabar durante a escrita do arquivo.
- Você pode ter limites de tamanho máximo de arquivo aplicados ao processo; para pipes, não.
- Porque o arquivo pode ser apagado/renomeado/truncado/modificado entre um comando gerador e outro (segundo exemplo).
- Porque o arquivo pode ser apagado/renomeado/truncado/modificado antes que o comando de leitura tenha a chance de começar a consumir dados.
É possível fazer a mesma coisa com redirecionamento em /dev/fd e/ou /proc.
exec 3< <(cmd1; cmd2; cmd3)
while read var <&3; do
...
done
exec 3<&-