No shell, o que significa “2> e 1”?

Em um shell Unix, se eu quiser combinar stderr e stdout no stream stdout para manipulação adicional, posso acrescentar o seguinte no final do meu comando:

 2>&1 

Então, se eu quiser usar head na saída do g++ , posso fazer algo assim:

 g++ lots_of_errors 2>&1 | head 

então eu posso ver apenas os primeiros erros.

Eu sempre tenho dificuldade em lembrar disso, e constantemente tenho que procurar, e é principalmente porque eu não entendo completamente a syntax desse truque em particular.

Alguém pode quebrar isso e explicar personagem por personagem o que significa 2>&1 ?

    O descritor de arquivo 1 é a saída padrão ( stdout ).
    O descritor de arquivo 2 é o erro padrão ( stderr ).

    Aqui está uma maneira de lembrar esse constructo (embora não seja totalmente preciso): no começo, 2>1 pode parecer uma boa maneira de redirect o stderr para o stdout . No entanto, ele será realmente interpretado como “redirect stderr para um arquivo chamado 1 “. & indica que o que segue é um descritor de arquivo e não um nome de arquivo. Então a construção se torna: 2>&1 .

     echo test > afile.txt 

    redireciona stdout para afile.txt . Isso é o mesmo que fazer

     echo test 1> afile.txt 

    Para redirect o stderr, você faz:

     echo test 2> afile.txt 

    >& é a syntax para redirect um stream para outro descritor de arquivo – 0 é stdin, 1 é stdout e 2 é stderr.

    Você pode redirect stdout para stderr fazendo:

     echo test 1>&2 # or echo test >&2 

    Ou vice-versa:

     echo test 2>&1 

    Então, resumindo … 2> redireciona stderr para um arquivo (não especificado), acrescentando &1 redireciona stderr para stdout.

    Alguns truques sobre redirecionamento

    Alguma particularidade de syntax sobre isso pode ter comportamentos importantes. Há algumas pequenas amostras sobre redirecionamentos, STDERR , STDOUT e ordenação de argumentos.

    1 – Sobrescrevendo ou anexando?

    Símbolo > redirecionamento médio.

    • > significa enviar como um arquivo completo , sobrescrevendo o alvo se existir (veja o recurso noclobber bash no # 3 depois).
    • >> mean send in addition to acrescentaria ao target se existir.

    Em qualquer caso, o arquivo seria criado se não existissem.

    2 – A linha de comando da shell depende da ordem!

    Para testar isso, precisamos de um comando simples que envie algo em ambas as saídas :

     $ ls -ld /tmp /tnt ls: cannot access /tnt: No such file or directory drwxrwxrwt 118 root root 196608 Jan 7 11:49 /tmp $ ls -ld /tmp /tnt >/dev/null ls: cannot access /tnt: No such file or directory $ ls -ld /tmp /tnt 2>/dev/null drwxrwxrwt 118 root root 196608 Jan 7 11:49 /tmp 

    (Esperando que você não tenha um diretório chamado /tnt , é claro;). Bem, nós temos isso !!

    Então, vamos ver:

     $ ls -ld /tmp /tnt >/dev/null ls: cannot access /tnt: No such file or directory $ ls -ld /tmp /tnt >/dev/null 2>&1 $ ls -ld /tmp /tnt 2>&1 >/dev/null ls: cannot access /tnt: No such file or directory 

    A última linha de comando despeja STDERR no console, e parece não ser o comportamento esperado … Mas …

    Se você quiser fazer alguma filtragem de postagem sobre uma saída, a outra ou ambas:

     $ ls -ld /tmp /tnt | sed 's/^.*$/< -- & --->/' ls: cannot access /tnt: No such file or directory < -- drwxrwxrwt 118 root root 196608 Jan 7 12:02 /tmp ---> $ ls -ld /tmp /tnt 2>&1 | sed 's/^.*$/< -- & --->/' < -- ls: cannot access /tnt: No such file or directory ---> < -- drwxrwxrwt 118 root root 196608 Jan 7 12:02 /tmp ---> $ ls -ld /tmp /tnt >/dev/null | sed 's/^.*$/< -- & --->/' ls: cannot access /tnt: No such file or directory $ ls -ld /tmp /tnt >/dev/null 2>&1 | sed 's/^.*$/< -- & --->/' $ ls -ld /tmp /tnt 2>&1 >/dev/null | sed 's/^.*$/< -- & --->/' < -- ls: cannot access /tnt: No such file or directory ---> 

    Observe que a última linha de comando neste parágrafo é exatamente igual à do parágrafo anterior, onde escrevi não parece ser o comportamento esperado (portanto, isso pode até ser um comportamento esperado).

    Bem, há alguns truques sobre redirecionamentos, para fazer uma operação diferente em ambas as saídas :

     $ ( ls -ld /tmp /tnt | sed 's/^/O: /' >&9 ) 9>&2 2>&1 | sed 's/^/E: /' O: drwxrwxrwt 118 root root 196608 Jan 7 12:13 /tmp E: ls: cannot access /tnt: No such file or directory 

    Nota: descritor &9 ocorreria espontaneamente devido a ) 9>&2 .

    Adenda: nota! Com a nova versão do bash ( >4.0 ), há um novo recurso e uma syntax mais sexy para fazer esse tipo de coisa:

     $ ls -ld /tmp /tnt 2> >(sed 's/^/E: /') > >(sed 's/^/O: /') O: drwxrwxrwt 17 root root 28672 Nov 5 23:00 /tmp E: ls: cannot access /tnt: No such file or directory 

    E, finalmente, para essa formatação de saída em cascata:

     $ ((ls -ld /tmp /tnt |sed 's/^/O: /' >&9 ) 2>&1 |sed 's/^/E: /') 9>&1| cat -n 1 O: drwxrwxrwt 118 root root 196608 Jan 7 12:29 /tmp 2 E: ls: cannot access /tnt: No such file or directory 

    Adenda: nota! Mesma nova syntax, nos dois sentidos:

     $ cat -n < (ls -ld /tmp /tnt 2> >(sed 's/^/E: /') > >(sed 's/^/O: /')) 1 O: drwxrwxrwt 17 root root 28672 Nov 5 23:00 /tmp 2 E: ls: cannot access /tnt: No such file or directory 

    Onde STDOUT passa por um filtro específico, STDERR para outro e finalmente ambas as saídas mescladas passam por um terceiro filtro de comando.

    3 – Uma palavra sobre a opção noclobber e >| syntax

    Isso é sobre sobrescrever :

    Enquanto set -o noclobber instrui o bash a não sobrescrever qualquer arquivo existente, o >| syntax permitem passar por esta limitação:

     $ testfile=$(mktemp /tmp/testNoClobberDate-XXXXXX) $ date > $testfile ; cat $testfile Mon Jan 7 13:18:15 CET 2013 $ date > $testfile ; cat $testfile Mon Jan 7 13:18:19 CET 2013 $ date > $testfile ; cat $testfile Mon Jan 7 13:18:21 CET 2013 

    O arquivo é sobregravado a cada vez, bem agora:

     $ set -o noclobber $ date > $testfile ; cat $testfile bash: /tmp/testNoClobberDate-WW1xi9: cannot overwrite existing file Mon Jan 7 13:18:21 CET 2013 $ date > $testfile ; cat $testfile bash: /tmp/testNoClobberDate-WW1xi9: cannot overwrite existing file Mon Jan 7 13:18:21 CET 2013 

    Passe com >| :

     $ date >| $testfile ; cat $testfile Mon Jan 7 13:18:58 CET 2013 $ date >| $testfile ; cat $testfile Mon Jan 7 13:19:01 CET 2013 

    Desmarcar esta opção e / ou perguntar se já está definido.

     $ set -o | grep noclobber noclobber on $ set +o noclobber $ set -o | grep noclobber noclobber off $ date > $testfile ; cat $testfile Mon Jan 7 13:24:27 CET 2013 $ rm $testfile 

    4 – Último truque e mais …

    Para redirect a saída de um determinado comando, vemos que uma syntax correta poderia ser:

     $ ls -ld /tmp /tnt >/dev/null 2>&1 

    para este caso especial , existe uma syntax de atalho: &> … ou >&

     $ ls -ld /tmp /tnt &>/dev/null $ ls -ld /tmp /tnt >&/dev/null 

    Nota: se 2>&1 existir, 1>&2 será uma syntax correta:

     $ ls -ld /tmp /tnt 2>/dev/null 1>&2 

    4b- Agora, vou deixar você pensar em:

     $ ls -ld /tmp /tnt 2>&1 1>&2 | sed -es/^/++/ ++/bin/ls: cannot access /tnt: No such file or directory ++drwxrwxrwt 193 root root 196608 Feb 9 11:08 /tmp/ $ ls -ld /tmp /tnt 1>&2 2>&1 | sed -es/^/++/ /bin/ls: cannot access /tnt: No such file or directory drwxrwxrwt 193 root root 196608 Feb 9 11:08 /tmp/ 

    4c- Se você estiver interessado em mais informações

    Você pode ler o bom manual pressionando:

     man -Len -Pless\ +/^REDIRECTION bash 

    em um console bash 😉

    Os números referem-se aos descritores de arquivo (fd).

    • Zero é stdin
    • Um é stdout
    • Dois é stderr

    2>&1 redireciona fd 2 para 1.

    Isso funciona para qualquer número de descritores de arquivos, se o programa os usar.

    Você pode olhar para /usr/include/unistd.h se você os esquecer:

     /* Standard file descriptors. */ #define STDIN_FILENO 0 /* Standard input. */ #define STDOUT_FILENO 1 /* Standard output. */ #define STDERR_FILENO 2 /* Standard error output. */ 

    Dito isso, escrevi ferramentas C que usam descritores de arquivo não padrão para registro em log personalizado, para que você não o veja, a menos que você o redirecione para um arquivo ou algo assim.

    Eu encontrei este post shiny sobre o redirecionamento: Tudo sobre redirecionamentos

    Redirecionar a saída padrão e o erro padrão para um arquivo

    $ comando &> arquivo

    Este one-liner usa o operador &> para redirect ambos os streams de saída – stdout e stderr – de comando para arquivo. Este é o atalho do Bash para redirect rapidamente os dois streams para o mesmo destino.

    Aqui está a aparência da tabela de descritores de arquivos depois que o Bash redirecionou os dois streams:

    Digite a descrição da imagem aqui

    Como você pode ver, stdout e stderr agora apontam para file . Então, qualquer coisa escrita no stdout e stderr é gravada no file .

    Existem várias maneiras de redirect os dois streams para o mesmo destino. Você pode redirect cada stream um após o outro:

    $ comando> arquivo 2> & 1

    Essa é uma maneira muito mais comum de redirect os dois streams para um arquivo. A primeira stdout é redirecionada para o arquivo e, em seguida, stderr é duplicado para ser o mesmo que stdout. Então, ambos os streams acabam apontando para o file .

    Quando o Bash vê vários redirecionamentos, ele os processa da esquerda para a direita. Vamos percorrer os passos e ver como isso acontece. Antes de executar qualquer comando, a tabela de descritores de arquivos do Bash se parece com isto:

    Digite a descrição da imagem aqui

    Agora o Bash processa o primeiro redirecionamento> arquivo. Já vimos isso antes e faz o stdout apontar para o arquivo:

    Digite a descrição da imagem aqui

    Próximo Bash vê o segundo redirecionamento 2> & 1. Nós não vimos este redirecionamento antes. Este duplica o descritor de arquivo 2 para ser uma cópia do descritor de arquivo 1 e obtemos:

    Digite a descrição da imagem aqui

    Ambos os streams foram redirecionados para o arquivo.

    No entanto, tenha cuidado aqui! Escrevendo

    comando> arquivo 2> & 1

    não é o mesmo que escrever:

    $ comando 2> & 1> arquivo

    A ordem dos redirecionamentos é importante no Bash! Este comando redireciona apenas a saída padrão para o arquivo. O stderr ainda imprimirá no terminal. Para entender por que isso acontece, vamos percorrer as etapas novamente. Portanto, antes de executar o comando, a tabela do descritor de arquivos é semelhante a esta:

    Digite a descrição da imagem aqui

    Agora o Bash processa os redirecionamentos da esquerda para a direita. Primeiro, ele vê 2> & 1 para duplicar stderr para stdout. A tabela de descritores de arquivos se torna:

    Digite a descrição da imagem aqui

    Agora o Bash vê o segundo redirecionamento, >file , e redireciona o stdout para o arquivo:

    Digite a descrição da imagem aqui

    Você vê o que acontece aqui? Stdout agora aponta para o arquivo, mas o stderr ainda aponta para o terminal! Tudo o que é gravado no stderr ainda é impresso na canvas! Portanto, tenha muito cuidado com a ordem dos redirecionamentos!

    Observe também que no Bash, escrevendo

    $ comando &> arquivo

    é exatamente o mesmo que:

    $ command> & arquivo

    Essa construção envia o stream de erro padrão ( stderr ) para a localização atual da saída padrão ( stdout ) – esse problema de moeda parece ter sido negligenciado pelas outras respostas.

    Você pode redirect qualquer identificador de saída para outro usando esse método, mas é mais frequentemente usado para canalizar streams stdout e stderr em um único stream para processamento.

    Alguns exemplos são:

     # Look for ERROR string in both stdout and stderr. foo 2>&1 | grep ERROR # Run the less pager without stderr screwing up the output. foo 2>&1 | less # Send stdout/err to file (with append) and terminal. foo 2>&1 |tee /dev/tty >>outfile # Send stderr to normal location and stdout to file. foo >outfile1 2>&1 >outfile2 

    Note que este último não direcionará stderr para outfile2 – ele o redireciona para o stdout quando o argumento foi encontrado ( outfile1 ) e então redireciona stdout para outfile2 .

    Isso permite alguns truques bastante sofisticados.

    2>&1 é uma construção de shell POSIX. Aqui está um detalhamento, token por token:


    2 : ” Erro padrão ” descritor de arquivo de saída.

    >& : Duplicar um operador do Descritor de Arquivo de Saída (uma variante do operador Redirecionamento de Saída > ). Dado [x]>&[y] , o descritor de arquivo denotado por x é feito para ser uma cópia do descritor de arquivo de saída y .

    1 descritor de arquivo de saída ” Saída padrão “.

    A expressão 2>&1 copia o descritor de arquivo 1 para o local 2 , portanto, qualquer saída gravada como 2 (“erro padrão”) no ambiente de execução vai para o mesmo arquivo originalmente descrito por 1 (“saída padrão”).


    Mais explicações:

    Descritor de Arquivo : “Um inteiro único, não negativo, por processo, usado para identificar um arquivo aberto para fins de access a arquivos.”

    Saída / erro padrão : Consulte a seguinte nota na seção Redirecionamento da documentação do shell:

    Os arquivos abertos são representados por números decimais que começam com zero. O maior valor possível é definido pela implementação; no entanto, todas as implementações devem suportar pelo menos 0 a 9, inclusive, para uso pelo aplicativo. Esses números são chamados de “descritores de arquivos”. Os valores 0, 1 e 2 têm significados especiais e usos convencionais e estão implícitos em certas operações de redirecionamento; eles são referidos como input padrão, saída padrão e erro padrão, respectivamente. Os programas geralmente recebem sua input da input padrão e gravam a saída na saída padrão. Mensagens de erro geralmente são escritas em erro padrão. Os operadores de redirecionamento podem ser precedidos por um ou mais dígitos (sem a permissão de caracteres intermediários) para designar o número do descritor de arquivo.

    Para responder à sua pergunta: Ela pega qualquer saída de erro (normalmente enviada para stderr) e grava na saída padrão (stdout).

    Isso é útil com, por exemplo, ‘mais’ quando você precisa de paginação para todas as saídas. Alguns programas gostam de imprimir informações de uso no stderr.

    Para ajudar você a lembrar

    • 1 = saída padrão (onde os programas imprimem saída normal)
    • 2 = erro padrão (onde os programas imprimem erros)

    “2> & 1” simplesmente aponta tudo enviado para stderr, para stdout.

    Eu também recomendo ler este post sobre o redirecionamento de erros onde este assunto é coberto em detalhes.

    2 é o erro padrão do console.

    1 é a saída padrão do console.

    Este é o Unix padrão, e o Windows também segue o POSIX.

    Por exemplo, quando você corre

     perl test.pl 2>&1 

    o erro padrão é redirecionado para a saída padrão, para que você possa ver as duas saídas juntas:

     perl test.pl > debug.log 2>&1 

    Após a execução, você pode ver toda a saída, incluindo erros, no debug.log.

     perl test.pl 1>out.log 2>err.log 

    Em seguida, a saída padrão vai para out.log e o erro padrão para err.log.

    Eu sugiro que você tente entender isso.

    Do ponto de vista de um programador, isso significa exatamente isso:

     dup2(1, 2); 

    Veja a man page .

    Compreender que 2>&1 é uma cópia também explica porque …

     command >file 2>&1 

    … não é o mesmo que …

     command 2>&1 >file 

    O primeiro enviará os dois streams para o file , enquanto o segundo enviará os erros para o stdout e a saída ordinária para o file .

    Pessoal, lembre – se sempre da dica do paxdiablo sobre a localização atual do alvo de redirecionamento … É importante.

    Meu mnemônico pessoal para o operador 2>&1 é o seguinte:

    • Pense em & como significando 'and' ou 'add' (o personagem é um amperse não é?)
    • Assim, torna-se: ‘redirect 2 (stderr) para onde 1 (stdout) já / atualmente é e adicionar ambos os streams’ .

    O mesmo mnemônico funciona para o outro redirecionamento freqüentemente usado, 1>&2 :

    • Pense em & significado and ou add … (você começa a idéia do e comercial, sim?)
    • Por isso, torna-se: ‘redirect 1 (stdout) para onde 2 (stderr) já / atualmente é e adicionar ambos os streams’ .

    E lembre-se sempre: você precisa ler cadeias de redirecionamentos “do final”, da direita para a esquerda ( não da esquerda para a direita).

    Desde que /foo não exista em seu sistema e /tmp faz…

     $ ls -l /tmp /foo 

    irá imprimir o conteúdo de /tmp e imprimir uma mensagem de erro para /foo

     $ ls -l /tmp /foo > /dev/null 

    irá enviar o conteúdo de /tmp para /dev/null e imprimir uma mensagem de erro para /foo

     $ ls -l /tmp /foo 1> /dev/null 

    fará exatamente o mesmo (observe o 1 )

     $ ls -l /tmp /foo 2> /dev/null 

    irá imprimir o conteúdo de /tmp e enviar a mensagem de erro para /dev/null

     $ ls -l /tmp /foo 1> /dev/null 2> /dev/null 

    irá enviar tanto a listview como a mensagem de erro para /dev/null

     $ ls -l /tmp /foo > /dev/null 2> &1 

    é taquigrafia

    Isto é exatamente como passar o erro para o stdout ou o terminal.

    Ou seja, o cmd não é um comando:

     $cmd 2>filename cat filename command not found 

    O erro é enviado para o arquivo assim:

     2>&1 

    Erro padrão é enviado para o terminal.

    Redirecionando Entrada

    O redirecionamento de input faz com que o arquivo cujo nome resulte da expansão da palavra a ser aberta para leitura no descritor de arquivo n, ou a input padrão (descritor de arquivo 0), se n não for especificado.

    O formato geral para redirect a input é:

     [n] 

    Redirecionando Saída

    O redirecionamento de saída faz com que o arquivo cujo nome resulte da expansão da palavra a ser aberta para escrita no descritor de arquivo n, ou a saída padrão (descritor de arquivo 1), se n não for especificado. Se o arquivo não existir, ele será criado; se existir, será truncado para o tamanho zero.

    O formato geral para redirect a saída é:

     [n]>word 

    Mover descritores de arquivos

    O operador de redirecionamento,

     [n]< &digit- 

    move o dígito do descritor de arquivo para o descritor de arquivo n ou a input padrão (descritor de arquivo 0), se n não for especificado. dígito é fechado depois de ser duplicado para n.

    Da mesma forma, o operador de redirecionamento

     [n]>&digit- 

    move o dígito do descritor de arquivo para o descritor de arquivo n ou a saída padrão (descritor de arquivo 1) se n não for especificado.

    Ref:

     man bash 

    Digite /^REDIRECT para localizar a seção de redirection e saiba mais ...

    Uma versão online está aqui: 3.6 Redirecionamentos

    PS:

    Muitas vezes, o man era a ferramenta poderosa para aprender Linux.

    0 para input, 1 para stdout e 2 para stderr.

    Uma dica : somecmd >1.txt 2>&1 está correto, enquanto somecmd 2>&1 >1.txt está totalmente errado sem efeito!