Ferramentas do usuário

Ferramentas do site


unix:shell_avancado

Diferenças

Aqui você vê as diferenças entre duas revisões dessa página.

Link para esta página de comparações

Ambos lados da revisão anterior Revisão anterior
unix:shell_avancado [2019/08/12 13:16]
maziero
unix:shell_avancado [2019/08/12 13:19] (atual)
maziero
Linha 1: Linha 1:
 +====== UNIX: Uso avançado do Shell ======
 +
 +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.
 +
 +===== Entradas e saídas padrão =====
 +
 +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:
 +
 +  * Entrada padrão (''​stdin''​ - //standard input//): onde o comando vai ler seus dados de entrada. No Bash, esse arquivo é referenciado pelo descritor 0.
 +  * Saída padrão (''​stdout''​ - //standard output//): onde o comando vai escrever seus dados de saída. No Bash, esse arquivo é referenciado pelo descritor 1.
 +  * Saída de erro (''​stderr''​ - //standard error//): onde o comando vai enviar mensagens de erro. No Bash, esse arquivo é referenciado pelo descritor 2.
 +
 +{{ processo.png }}
 +
 +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.
 +
 +{{ desv-terminal.png }}
 +
 +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:​
 +
 +<​code>​
 +~> rev
 +vamos fazer um teste
 +etset mu rezaf somav                   *
 +temos que achar um palindromo
 +omordnilap mu rahca euq somet          *
 +opoetaamaateopo
 +opoetaamaateopo ​                       *
 +^D
 +~>
 +</​code>​
 +
 +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'':​
 +
 +<​code>​
 +~> sort
 +joao
 +maria
 +antonio
 +carlos
 +manoel
 +^D
 +antonio carlos joao manoel maria
 +~>
 +</​code>​
 +
 +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.
 +
 +===== Redireção para arquivos =====
 +
 +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:
 +
 +{{ desv-arquivos.png }}
 +
 +<note important>​
 +A sintaxe de redireção é específica para cada shell, isto é, não é a mesma entre o C-Shell e o Bourne Shell; aqui será apresentada a sintaxe do shell Bash.
 +</​note>​
 +
 +Os principais operadores de redireção para arquivos são:
 +
 +  * Saída em arquivo: a saída padrão (//​stdout//​) do comando é desviada para um arquivo usando o operador ''>'':​
 +
 +<​code>​
 +~> ls > listagem.txt
 +</​code>​
 +
 +  * Entrada de arquivo: a entrada padrão (//stdin//) pode ser obtida a partir de um arquivo usando o operador ''<'':​
 +
 +<​code>​
 +~> rev < listagem.txt
 +</​code>​
 +
 +  * Uso combinado: os dois operadores podem ser usados simultaneamente.
 +
 +<​code>​
 +~> rev < listagem.txt > listrev.txt
 +</​code>​
 +
 +  * Concatenação:​ a saída padrão pode ser concatenada a um arquivo existente usando-se o operador ''>>'',​ como mostra o exemplo:
 +
 +<​code>​
 +~> ls /etc >> listagem.txt
 +</​code>​
 +
 +  * Saída de erros: a saída de erros (//​stderr//​) também pode ser redirecionada,​ através do operador ''​2>''​ (que faz referência ao descritor 2):
 +
 +<​code>​
 +~> 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
 +</​code>​
 +
 +  * As saídas padrão e de erro podem ser redirecionadas de forma independente:​
 +
 +<​code>​
 +~> 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 ​
 +</​code>​
 +
 +  * Além disso, a saída de erro pode ser sobreposta à saída padrão:
 +
 +<​code>​
 +~> 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
 +</​code>​
 +
 +  * Forçar um desvio: Caso a saída seja redirecionada para um arquivo já existente, o shell recusa a operação indicando o erro (somente se a variável ''​noclobber''​ estiver setada através do comando ''​set -C''​). Essa operação pode ser forçada através do operador ''​!'':​
 +
 +<​code>​
 +~> ls > teste.txt
 +teste.txt: File exists.
 +
 +~> ls >! teste.txt
 +
 +~> ls >> novo.txt
 +novo.txt: No such file or directory
 +
 + ~> ls >>! novo.txt
 +</​code>​
 +
 +===== Redireção usando pipes =====
 +
 +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:
 +
 +{{ desv-pipes.png }}
 +
 +É 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:
 +
 +<​code>​
 +~> ls -l /etc | more
 +~> ls -l /tmp | sort | more
 +~> ls -l /usr/bin | cut -c31-40 | sort | more
 +</​code>​
 +
 +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.
 +
 +===== Filtros =====
 +
 +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:
 +
 +<code c filtro.c>​
 +#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);
 +}
 +</​code>​
 +
 +Para compilar esse filtro basta digitar: ''​gcc -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ão
 +  * ''​tac''​ : idem, mas inverte a ordem das linhas
 +  * ''​more''​ : permite a paginação do fluxo de dados
 +  * ''​tr''​ : troca de caracteres entre dois conjuntos
 +  * ''​head''​ : seleciona as ''​n''​ linhas iniciais do fluxo de dados
 +  * ''​tail''​ : seleciona as ''​n''​ linhas finais do fluxo de dados
 +  * ''​wc''​ : conta o número de linhas, palavras e bytes do fluxo
 +  * ''​sort''​ : ordena as linhas segundo critérios ajustáveis
 +  * ''​uniq''​ : remove linhas repetidas, deixando uma só linha
 +  * ''​sed''​ : para operações complexas de strings (trocas, etc)
 +  * ''​grep''​ : seleciona linhas contendo uma determinada expressão
 +  * ''​cut''​ : seleciona colunas do fluxo de entrada
 +  * ''​rev''​ : reverte a ordem dos caracteres de cada linha do fluxo de entrada
 +  * ''​tee''​ : duplica o fluxo de entrada (para um arquivo e para a saída standard)
 +  * ... : qualquer programa que leia dados de stdin e escreva sua saída em stdout pode ser usado como filtro
 +
 +Para conhecer melhor cada um dos comandos acima, basta consultar suas respectivas páginas de manual.
 +
 +===== Exercícios =====
 +
 +  - Usando comandos e //pipes//, determine o número de linhas da página de manual do shell Bash.
 +  - Determine quanto arquivos normais (não diretórios nem links) existem em ''/​usr''​.
 +  - Monte uma linha de comandos usando //pipes// para identificar todos os usuários proprietários de arquivos ou diretórios a partir de''​ /​tmp'',​ colocando o resultado no arquivo ''​users-tmp.txt''​. Siga os seguintes passos:
 +    * Use o comando ''​find ''​para listar os proprietários de todos os arquivos dentro de ''/​tmp''​ (dica: use a opção ''​-printf''​ do comando ''​find''​).
 +    * Ordene a listagem obtida, usando o comando ''​sort''​
 +    * Remova as linhas repetidas, usando o comando ''​uniq''​
 +    * Direcione a saída para o arquivo indicado ''​users-tmp.txt''​.
 +  - Use o comando cut na saída de um comando ls -l para mostrar apenas as permissões dos arquivos no diretório /etc. Depois use sort e uniq para mostrar quantas permissões diferentes existem naquele diretório.
 +  - Quantos arquivos invisíveis (iniciados com .) há na sua área HOME?
 +  - Quantos diretórios há na sua área HOME?
 +  - Liste todos os atributos de todos os arquivos de um diretório e utilize o cut para mostrar apenas suas permissões e seu nome.
 +  - Liste todos os arquivos e seus atributos (somente os arquivos, diretórios não devem aparecer) do diretório /etc, ordenando a saída por data do arquivo, e guarde a saída no arquivo teste.txt na sua área.
 +  - Mostre apenas o vigésimo arquivo do diretório /etc
 +  - Mostre apenas os arquivos e diretórios para os quais você tem permissão de execução na sua área HOME.
 +  - Acesse o servidor ssh.inf.ufpr.br. Utilize o comando finger para mostrar o Login de todos usuários cujo primeiro nome seja Daniel.
 +  - Execute os comandos a seguir como usuário normal. Determine o que é stdin, stdout e stderr para cada comando (o conteúdo de cada fluxo para cada comando):
 +    - ''​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''​
 +    - Confira seu resultado repetindo os comandos e atribuindo //stdout// para ''​$HOME/​saida.txt''​ e //stderr// para ''​$HOME/​erro.txt''​.
 +  - Observe as seguintes sequências de comandos e responda às perguntas: <​code>​
 +$ mkdir vazio
 +$ cd vazio
 +$ cp a b
 +cp: cannot stat '​a':​ No such file or directory
 +$ cp a b >a
 +</​code>​
 +    - Por que não há mensagem de erro após o segundo comando ''​cp''?​ Qual o conteúdo do arquivo ''​a''?​ <​code>​
 +$ 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
 +</​code>​
 +    - Por que o arquivo ''​b''​ está vazio? O que há no arquivo ''​a''?​
  
unix/shell_avancado.txt · Última modificação: 2019/08/12 13:19 por maziero