Redirecionamentos no Bash

Curso de Bash

Seção do curso sobre redirecionamentos.

Entrada padrão (ou o acrônimo em inglês stdin) é um dos 3 canais de comunicação padrão entre um processo e seu ambiente. Nesse canal os dados são originados no ambiente e trafegam em destino ao processo.

É dito que um programa lê dados da entrada padrão quando digitamos os caracteres em um terminal (ou outro ambiente) e tais caracteres são buscados pelo programa.

Saída padrão (stout) é o destino dos dados produzidos por um processo. Tipicamente conectado ao terminal.

Erro padrão (stderr) também é um canal de saída, mas é utilizado apenas para dar saída às mensagens de erro.

Conteúdo

  1. Origem da entrada padrão
  2. Lendo dados da entrada padrão
  3. Redirecionamento de entrada
  4. Redirecionamento da saída
  5. Redirecionamento de erro padrão
  6. Redirecionando erro e saída padrão simultaneamente
  7. Verificando os descritores de arquivo
  8. Exercícios

Origem da entrada padrão

A entrada padrão é representada pelo descritor de arquivo 0 (do inglês, file descriptor), que é um link com o caminho /proc/<PID>/fd/0, onde <PID> é substituído pelo PID do processo.

Por padrão esse link aponta para um arquivo que representa um terminal.

O comando tty exibe o nome do arquivo que representa o terminal.

tty
/dev/pts/1

Abaixo podemos verificar que a entrada padrão do processo com PID 5311 está conectada ao terminal /dev/pts/1.

ls -l /proc/5311/fd/0
lrwx------ 1 caio caio 64 Dec  6 10:00 /proc/5311/fd/0 -> /dev/pts/1

Lendo dados da entrada padrão

- pode ser utilizado como argumento para que o comando suportado leia dados da entrada padrão.

Vários dos comandos, especialmente para processamento de texto, aceitam - como argumento geralmente no lugar que seria de um arquivo de texto.

O argumento - facilita a entrada de dados já que linhas podem ser digitadas diretamente no terminal, evitando assim a criação de um arquivo.

- é opcional quando nenhum outro argumento é especificado. shuf, sort, cat, tac, head, tail, wc são exemplos de comandos que leem da entrada padrão quando nenhum argumento é especificado ou quando - é especificado.

shuf

Logo após digitarmos o nome do comando e pressionarmos Enter, o cursor é movido para a linha seguinte. A partir daí qualquer caractere digitado fará parte da entrada, incluíndo o caractere novalinha que é inserido quando pressionamos Enter.

Ctrl + D envia um caractere chamado EOF ou End of File (fim do arquivo, em português) para indicar o término da entrada. Ctrl + D deve ser pressionado uma vez quando o cursor está em uma linha vazia e duas vezes quando há caracteres na linha.

Assim que terminada a entrada de dados o comando é executado.

Na entrada abaixo Ctrl + D é representado por ^D apenas para ilustrar o conceito, o atalho não é exibido.

Z
D
F
H
^D

A saída inicia na linha em que Ctrl + D foi pressionado.

H
Z
F
D

- é necessário quando há outros argumentos. > abaixo indica as linhas digitadas pois a entrada e saída estão intercaladas.

head -n 2 /etc/hosts -
==> /etc/hosts <==
127.0.0.1   localhost
127.0.1.1   FX505DV

==> standard input <==
> A
A
> B
B

Redirecionamento de entrada

É representado por < e redireciona a entrada padrão para o arquivo (ou outro recurso) à sua direita.

O arquivo letras é criado abaixo contendo as letras de A até D, cada uma em uma linha.

printf "%s\n" {A..D} > letras

A entrada padrão de wc é redirecionada para o arquivo letras.

< letras wc
4 4 8

O uso abaixo, com o redirecionamento à direita do comando, tem efeito idêntico e é a forma mais comum.

wc < letras
4 4 8

Here Documents

Tipo de redirecionamento da entrada padrão que permite especificar as linhas diretamente no terminal.

É especificado com o operador << <palavra> onde <palavra> é a sequência que determina o fim da entrada.

Difere de - pois a entrada é terminada com <palavra> ao invés de Ctrl + D.

O operador << abaixo determina que a linha contendo fim, sem nenhum caractere o precedendo ou sucedendo, encerra o here-document.

tr -d "[:digit:]" << fim
A1B2
C3
fim 4
fim

Saída

AB
C
fim

Expansão de variável, substituição de comando e expansão aritmética também são interpretadas (conceitos abordados em capítulos futuros).

tac << ultima_linha
  Número aleatório $RANDOM
  Diretório atual $(pwd)
  Exponenciação $(( 2 ** 10))
ultima_linha

Saída

  Exponenciação 1024
  Diretório atual /home/caio
  Número aleatório 315

Para evitar qualquer expansão basta colocar o delimitador entre "" ou ''. Contudo o delimitador da última linha da entrada deve aparecer sem as aspas.

tac << "ultima_linha"
  Exponenciação $(( 2 ** 10))
  Diretório atual $(pwd)
  Número aleatório $RANDOM
ultima_linha

⚠️ Ctrl + D na entrada padrão ocasiona um aviso na saída apesar de processar todas as linhas posteriores.

tr "[:lower:]" "[:upper:]" << termino
> Uma linha
> ^D
> bash: warning: here-document at line 43 delimited by end-of-file (wanted `termino')
UMA LINHA

Here Strings

O operador <<< realiza o redirecionamento da entrada padrão para a palavra à sua direita. A palavra é chamada de here_string.

wc <<< A
1 1 2

❌ Especificar mais de um operando é um erro. Bash interpreta as palavras adicionais como argumentos.

wc <<< A B C
wc: B: No such file or directory
wc: C: No such file or directory
0 0 0 total

Aspas podem ser utilizadas para esse fim.

wc <<< "A B C"
1 3 6

Aspas também podem ser utilizadas para inserir novalinha na here-string.

wc -l <<< "A
B C"
2

Expansão de variável, substituição de comando e expansão aritmética são interpretadas na here-string. Conceitos abordados em capítulos futuros.

cat <<< "$BASH_VERSION $(date) $((~-2))"
5.0.17(1)-release Sun 06 Dec 2020 17:25:30 -03 1

Redirecionamento da saída

Assim como a entrada padrão, a saída padrão e o erro padrão são tipicamente conectados ao terminal.

tty
/dev/pts/1

Saída padrão tem o descritor de arquivo 1 e o erro padrão 2.

ls -l /proc/5080/fd
lrwx------ 1 caio caio 64 Dec  7 09:25 0 -> /dev/pts/1
lrwx------ 1 caio caio 64 Dec  7 09:25 1 -> /dev/pts/1
lrwx------ 1 caio caio 64 Dec  7 09:25 2 -> /dev/pts/1

O operador de redirecionamento > redireciona a saída do comando para o arquivo à sua direita. Caso o arquivo não exista, é criado. Caso já exista é sobrescrito.

O comando date tem sua saída redirecionada para o arquivo data_e_hora e então o arquivo tem seu conteúdo exibido por head.

date > data_e_hora
head data_e_hora
Mon 07 Dec 2020 10:22:08 -03

Caso utilizemos o arquivo novamente como operando de >, ele será sobrescrito.

ps > data_e_hora
head data_e_hora
    PID TTY          TIME CMD
   5080 pts/1    00:00:00 bash
   9766 pts/1    00:00:00 ps

Já o operador >> insere a saída ao fim do operando (o arquivo à sua direita). Caso o arquivo não exista, é criado.

whoami >> data_e_hora
    PID TTY          TIME CMD
   5080 pts/1    00:00:00 bash
   9766 pts/1    00:00:00 ps
caio

Além de arquivos comuns, é possível utilizar arquivos especiais como abaixo, em que a saída é redirecionada para outro terminal.

groups > /dev/pts/2

Saída no terminal /dev/pts/2, logo após o prompt.

caio@FX505DV:~/temp$ caio adm cdrom sudo dip plugdev lpadmin lxd sambashare

Redirecionamento de erro padrão

2> e 2>> redirecionam as mensagems de erro como os operadores > e >> fazem com a saída regular.

ls /inexistente 2> errors
tail erros
ls: cannot access '/inexistente': No such file or directory

É possível ignorar as mensagens de erro ou mesmo a saída padrão redirecionando-as para /dev/null.

mkdir -v . .. um_dir 2> /dev/null
mkdir: created directory 'um_dir'

Mais de um redirecionamento pode ser especificado para um mesmo comando.

Abaixo cat envia para a saída padrão (redirecionada para o meu_arquivo) o que foi lido da entrada padrão (redicionada para a Uma linha) e tail exibe o conteúdo do recém criado meu_arquivo.

cat > meu_arquivo <<< "Uma linha"
tail meu_arquivo
Uma linha

Redirecionando erro e saída padrão simultaneamente

O operador &> redireciona ambas as saídas (saída padrão e erro padrão) para o arquivo à direita. O arquivo é criado caso não exista e sobrescrito caso exista, como ocorre com > e 2>.

mkdir -v .. . dir1 dir2 &> saidas
head saidas
mkdir: cannot create directory ‘..’: File exists
mkdir: cannot create directory ‘.’: File exists
mkdir: created directory 'dir1'
mkdir: created directory 'dir2'

Verificando os descritores de arquivo

No primeiro terminal inicie nova sessão de Bash redirecionando sua saída e erro padrão para o arquivo historico.

bash &> historico

No segundo terminal execute tail -F para acompanhar as inserções de linha.

tail -F historico

De volta ao primeiro, execute o comando abaixo para obter o PID da sessão de Bash.

echo $$

PID exibido na saída no segundo terminal.

29316

Ainda no primeiro terminal, exiba os descritores de arquivo para a sessão de Bash.

ls -l /proc/29316/fd

Saída no segundo.

29316
total 0
lrwx------ 1 caio caio 64 Dec  7 15:26 0 -> /dev/pts/1
l-wx------ 1 caio caio 64 Dec  7 15:26 1 -> /home/caio/historico
l-wx------ 1 caio caio 64 Dec  7 15:26 2 -> /home/caio/historico

Ctrl + D no primero para sair da sessão de Bash e Ctrl + C no segundo para interromper tail.

Exercícios

Selecione as afirmações verdadeiras

Comandos que leem linhas da entrada padrão
Escrito por Caio Santesso.

Comentários

  • Conteúdo dos posts, exceto onde indicado contrário, licenciado sob a licença CC BY-SA 4.0 .