Os operadores de redirecionamento sempre abrem descritores de arquivos em paralelo?

7

1. Considere o snippet 1:

$ cat test.txt > test.txt
cat: test.txt: input file is output file

Parece que cat faz seu descritor de arquivo de entrada apontar para test.txt e, em seguida, quando ele tenta definir seu descritor de arquivo de saída para test.txt, ele lança o erro acima. Aqui parece que cat está ciente do operador de redirecionamento e, portanto, continua tentando definir o descritor do arquivo de saída como test.txt

2. Considere o snippet 2:

$ cat 1.txt
1:CAT
2:dog
$ sed 's/cat/CAT/g' test.txt
1:CAT
2:dog
$ sed 's/cat/CAT/g' test.txt > test.txt
$ cat test.txt # Note that test.txt is now empty
$

Aqui vemos que sed abre o test.txt (último argumento) no modo de leitura e ao mesmo tempo define test.txt como seu descritor de saída de arquivo. Além disso, o operador '>' sobrescreve o conteúdo do arquivo BEFORE sed começa a ler a partir dele.

Estou ciente de que os comandos em um pipeline são executados em paralelo, mas não encontrei informações sobre como os operadores de redirecionamento se comportam. Quaisquer links de suporte seriam úteis.

    
por Kent Pawar 11.06.2013 / 18:23

2 respostas

11

Além da documentação apontada por jordanm, quero ter certeza de corrigir um equívoco ilustrado em sua pergunta - o programa executado não lida com redirecionamentos. É quase nem mesmo ciente deles. O shell lida com redirecionamentos.

Um programa é iniciado com três arquivos abertos: stdin (# 0), stdout (# 1) e stderr (# 2). Se você acabou de executar um programa a partir do seu prompt de shell, estes serão conectados ao seu dispositivo terminal, assim o programa lê o que você digita (stdin), e imprime saída (stdout) e erros (stderr) para o seu terminal.

Como exemplo, apenas corro cat em um terminal (que tty diz é /dev/pts/31 ). Posso verificar quais arquivos foram abertos com lsof :

$ lsof -a -p 'pidof cat' -d0,1,2
COMMAND   PID    USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
cat     21257 anthony    0u   CHR 136,31      0t0   34 /dev/pts/31
cat     21257 anthony    1u   CHR 136,31      0t0   34 /dev/pts/31
cat     21257 anthony    2u   CHR 136,31      0t0   34 /dev/pts/31

De fato, podemos ver que o terminal está aberto para todos os três. Agora, em vez disso, vamos tentar uma invocação de gato um pouco boba: cat < /dev/zero > /dev/null 2>/dev/full , que está redirecionando os três:

COMMAND   PID    USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
cat     21838 anthony    0r   CHR    1,5      0t0 1030 /dev/zero
cat     21838 anthony    1w   CHR    1,3      0t0 1028 /dev/null
cat     21838 anthony    2w   CHR    1,7      0t0 1031 /dev/full

O shell implementou esses redirecionamentos passando os três dispositivos como stdin, stdout e stderr (em vez do terminal). O shell implementa de forma semelhante os tubos. Vamos tentar cat | dd > /dev/null (um cachimbo bastante bobo, de fato):

COMMAND   PID    USER   FD   TYPE DEVICE SIZE/OFF     NODE NAME
cat     22507 anthony    0u   CHR 136,31      0t0       34 /dev/pts/31
cat     22507 anthony    1w  FIFO    0,8      0t0 56081395 pipe
cat     22507 anthony    2u   CHR 136,31      0t0       34 /dev/pts/31

COMMAND   PID    USER   FD   TYPE DEVICE SIZE/OFF     NODE NAME
dd      22508 anthony    0r  FIFO    0,8      0t0 56081395 pipe
dd      22508 anthony    1u   CHR 136,31      0t0       34 /dev/null
dd      22508 anthony    2u   CHR 136,31      0t0       34 /dev/pts/31

Observe como o shell abriu um pipe e o usou para conectar o stdout de cat ao stdin de dd . Além disso, como ele conectou o stdout de dd a /dev/null .

Os comandos que estão sendo executados não estão realmente conscientes dos redirecionamentos. Eles apenas usam stdin, stdout, stderr normalmente. Todos poderiam ser o terminal, ou poderiam ser redirecionados para / de um arquivo, um dispositivo ou talvez um canal para outro programa. Ou até mesmo um socket de rede, se o seu shell suportar isso.

Até mesmo os pipelines mais ridiculamente complicados são na verdade apenas instruções para o shell sobre como conectar esses três identificadores de arquivos antes de executar o programa.

(NOTA: Alguns programas se comportam de maneira diferente no caso de um deles estar conectado a um terminal, mas normalmente é mais amigável no uso interativo. Por exemplo, ls alterna para saída de coluna única e sem cor Quando o stdout não é um terminal - que geralmente é o que você quer se você está prestes a passá-lo para outro programa. Alguns programas lidam com o prompt diferente se o stdin não for um terminal. E assim por diante.

    
por 11.06.2013 / 19:22
10

O redirecionamento acontece primeiro no shell. No seu exemplo:

cat test.txt > test.txt

A primeira coisa que acontece é o bash abrir test.txt , que trunca o arquivo. Agora está vazio, antes que cat seja executado com test.txt como argumento.

Na seção de redirecionamento da bash manpage:

Before a command is executed, its input and output may be redirected using a special notation interpreted by the shell. Redirection may also be used to open and close files for the current shell execution environment. The following redirection operators may precede or appear anywhere within a simple command or may follow a command. Redirections are processed in the order they appear, from left to right.

Eu não vejo nada na especificação POSIX para indicar que ela deve ocorrer primeiro, mas eu não estou ciente de um shell onde isso não ocorre.

    
por 11.06.2013 / 18:29