Neste texto são apresentados os principais conceitos associados a entradas e saídas padrão, como redirecionamentos e pipes
. Também são vistos uma série de programas simples (os filtros), que podem ser muito úteis quando associados através de pipes.
A maioria dos comandos UNIX pode comunicar-se com o sistema através de descritores de arquivos especiais conhecidos como entradas e saídas padrão. Eles são:
stdin
- standard input): onde o comando vai ler seus dados de entrada. No Bash, esse arquivo é referenciado pelo descritor 0.stdout
- standard output): onde o comando vai escrever seus dados de saída. No Bash, esse arquivo é referenciado pelo descritor 1.stderr
- standard error): onde o comando vai escrever mensagens de erro. No Bash, esse arquivo é referenciado pelo descritor 2.Quando um comando é lançado sem indicar seu arquivo de trabalho, ele busca seus dados da entrada padrão. Por default, o shell onde o comando foi lançado associa o processo ao seu terminal, ou seja: a entrada padrão do processo é associada ao teclado e as saídas padrão e de erros à tela da sessão corrente.
Um exemplo de uso da entrada e saída padrão é o comando rev
, que escreve em sua saída padrão as linhas de texto lidas em sua entrada padrão, invertendo-as:
$ rev vamos fazer um teste etset mu rezaf somav * temos que achar um palindromo omordnilap mu rahca euq somet * opoetaamaateopo opoetaamaateopo * ^D $
No exemplo, as linhas marcadas com *
indicam as saídas geradas pelo comando rev. O caractere ^D
(Control-D) no final indica o final da entrada padrão (ou seja, o fim de arquivo). Ao receber esse caractere, o comando rev
encerra sua execução, pois chegou ao final de seu arquivo de entrada (que neste caso é o teclado). Outro exemplo de uso da entrada e saída padrão é comando sort
:
$ sort joao maria antonio carlos manoel ^D antonio carlos joao manoel maria $
Normalmente o shell direciona a entrada padrão para o teclado e a saída padrão para a tela da sessão do usuário, mas ele pode ser instruído para redirecioná-las para arquivos ou mesmo para outros programas, como será visto na seqüência.
O shell pode redirecionar as entrada e saídas padrão de comandos para arquivos normais no disco, usando operadores de redireção, como mostra a figura abaixo:
Os principais operadores de redireção para arquivos são:
>
:$ ls > listagem.txt
<
:$ rev < listagem.txt
$ rev < listagem.txt > listrev.txt
>>
, como mostra o exemplo:$ ls /etc >> listagem.txt
2>
(que faz referência ao descritor 2):$ ls /xpto > teste.txt ls: /xpto: No such file or directory $ ll /xpto 2> erro.txt $ cat error.txt ls: /xpto: No such file or directory
$ ll /xpto /etc/passwd > acerto.txt 2> erro.txt $ cat error.txt ls: /xpto: No such file or directory $ cat acerto.txt -rw-r--r-- 1 root root 2136 Mai 14 17:02 /etc/passwd
$ ll /xpto /etc/passwd > acerto.txt 2>&1 $ cat acerto.txt -rw-r--r-- 1 root root 2136 Mai 14 17:02 /etc/passwd ls: /xpto: No such file or directory
noclobber
estiver setada através do comando set -C
). Essa operação pode ser forçada através do operador !
:$ ls > teste.txt teste.txt: File exists. $ ls >! teste.txt $ ls >> novo.txt novo.txt: No such file or directory $ ls >>! novo.txt
O shell permite a construção de comandos complexos através da combinação de vários comandos simples. O operador |
, conhecido como pipe, ou tubo, permite conectar a saída padrão de um comando à entrada padrão de outro. Com isso, um mesmo fluxo de dados pode ser tratado por diversos comandos consecutivamente, como mostra a figura:
É importante ressaltar que os comandos conectados são lançados simultaneamente pelo shell e executam ao mesmo tempo. O shell controla a execução de cada um para que não haja acumulo de dados entre os comandos (a cada pipe é associado um buffer de tamanho limitado).
A sintaxe usada para redireção é simples. Eis alguns exemplos:
$ ls -l /etc | more $ ls -l /tmp | sort | more $ ls -l /usr/bin | cut -c31-40 | sort | more
O mecanismo de redireção de entrada/saída é genérico, ou seja, funciona para qualquer programa que use as entradas e saídas padrão, em qualquer linguagem de programação.
Um filtro é basicamente um programa que lê dados da entrada padrão, realiza algum processamento e escreve os dados resultantes na saída padrão. Um exemplo simples de filtro seria:
#include <stdio.h> #include <stdlib.h> // lê caracteres em stdin e escreve em stdout, convertendo // vogais minúsculas em '*' e vogais maiúsculas em '#'. int main () { char c ; c = getchar () ; while (c != EOF) { switch (c) { case 'a': case 'e': case 'i': case 'o': case 'u': c = '*' ; break ; case 'A': case 'E': case 'I': case 'O': case 'U': c = '#' ; break ; } putchar (c) ; c = getchar () ; } return (0); }
Para compilar esse filtro basta digitar: gcc -Wextra -o filtro filtro.c
. Uma vez compilado, o arquivo executável filtro
pode ser usado nas linha de comando UNIX, como qualquer outro filtro.
Existe um grande número de comandos UNIX bastante simples, cujo uso direto é pouco útil, mas que podem ser de grande valia quando associados entre si através de pipes. Esses comandos são chamados filtros, porque funcionam como filtros para o fluxo de dados. Eis alguns filtros de uso corrente:
cat
: concatena diversos arquivos na saída padrãotac
: idem, mas inverte a ordem das linhasmore
: permite a paginação do fluxo de dadostr
: troca de caracteres entre dois conjuntoshead
: seleciona as n
linhas iniciais do fluxo de dadostail
: seleciona as n
linhas finais do fluxo de dadoswc
: conta o número de linhas, palavras e bytes do fluxosort
: ordena as linhas segundo critérios ajustáveisuniq
: remove linhas repetidas, deixando uma só linhased
: para operações complexas de strings (trocas, etc)grep
: seleciona linhas contendo uma determinada expressãocut
: seleciona colunas do fluxo de entradarev
: reverte a ordem dos caracteres de cada linha do fluxo de entradatee
: duplica o fluxo de entrada (para um arquivo e para a saída standard)Para conhecer melhor cada um dos comandos acima, basta consultar suas respectivas páginas de manual.
/usr
. /tmp
, colocando o resultado no arquivo users-tmp.txt
. Siga os seguintes passos:find
para listar os proprietários de todos os arquivos dentro de /tmp
(dica: use a opção -printf
do comando find
).sort
uniq
users-tmp.txt
.cat nonexistentfile
file /sbin/ifconfig
grep root /etc/passwd /etc/nofiles > grepresults
/etc/init.d/sshd start > /var/tmp/output
/etc/init.d/crond start > /var/tmp/output 2>&1
$HOME/saida.txt
e stderr para $HOME/erro.txt
.$ mkdir vazio $ cd vazio $ cp a b cp: cannot stat 'a': No such file or directory $ cp a b >a
cp
? Qual o conteúdo do arquivo a
? $ date >a $ cat a Wed Feb 8 03:01:21 EST 2012 $ cp a b $ cat b Wed Feb 8 03:01:21 EST 2012 $ cp a b >a $ cat b
b
está vazio? O que há no arquivo a
?