Unconfigured Ad Widget

Collapse

Anúncio

Collapse
No announcement yet.

Curso de Shell - Aula 2

Collapse
X
 
  • Filter
  • Tempo
  • Show
Clear All
new posts

  • Font Size
    #1

    Curso de Shell - Aula 2

    Por: Alex Borro

    Introdução

    Na aula de hoje vamos falar sobre execução de programas em primeiro plano (fg - foreground) e em segundo plano (bg - background), redirecionamento de saídas e também sobre os códigos de escape dos programas.

    Execução em foreground e background

    Quando executamos um programa, o shell fica esperando o mesmo terminar para depois nos devolver a linha de comando. Por exemplo, quando executamos o comando cp arquivo1 arquivo2,o shell executa esse comando, fica esperando ele terminar, para depois nos retornar a linha de comando. Isso chama-se execução em primeiro plano, ou foreground, em inglês.Agora digamos que o arquivo a ser copiado seja muito grande, digamos, 50Mb. Enquanto o comando cp é executado, vamos ficar com o shell preso a ele todo esse tempo, ou seja, cerca de 1 ou 2 minutos. Somente após isso vamos ter a linha de comando de volta para podermos continuar trabalhando.

    E se pudéssemos dizer ao shell para executar um programa e nos retornar a linha de comando sem ficar esperando o tal programa terminar? Seria muito melhor, não? Em alguns casos seria. E podemos fazer isso.

    Uma maneira fácil é colocar o sinal de & depois de um comando. No exemplo acima ficaria:

    neo@matrix:~$ cp arquivo1 arquivo2 &
    [1] 206
    neo@matrix:~$

    Pronto, assim que teclarmos [enter], teremos a nossa linha de comando de volta e mais duas informações: "[1] 206".

    A primeira informação ([1]) chama-se job. Ela identifica os programas que estão sendo executados em bg (background). Por exemplo, se executarmos mais um programa em bg enquanto este "cp" está sendo executado, o novo programa recebe o job de número 2 ([2]) e assim por diante.

    A segunda informação (206) é o pid do programa, ou seja, o número de processo que o kernel dá a esse programa.

    Mas aí temos um pequeno problema. Digamos que você queira trazer o programa para fg, por exemplo, se o programa executado em bg for um tocador de mp3 e você quiser mudar a música. Como fazemos? Usamos o comando fg [job] (intuitivo, não ?) do bash. No exemplo acima, digamos que eu execute o "cp" em bg, mas depois queira trazê-lo para fg para cancelá-lo. Seria simples:

    neo@matrix:~$ cp arquivo1 arquivo2 &
    [1] 206
    neo@matrix:~$ fg 1
    cp arquivo1 arquivo2

    Assim trazemos o "cp" para primeiro plano e a linha de comando só retorna quando ele terminar.

    Opcional

    Uma outra maneira de colocar um programa para rodar em bg é utilizando um truque do bash (não sei se esta opção está disponível em outros shells).Digamos que você execute o comando "cp" e esqueça de colocar o sinal "&". E aí? Tem que ficar esperando acabar ou cancelar o comando? Não, podemos teclar: Ctrl + Z.

    Ao fazer isso, paramos a execução do programa. Então é só dar o comando bg [job] (intuitivo também, né?):

    neo@matrix:~$ cp arquivo1 arquivo2

    * aqui teclamos Ctrl + Z *
    [1]+ Stopped cp -i arquivo1 arquivo2
    neo@matrix:~$ bg 1
    [1]+ cp -i arquivo1 arquivo2 &
    neo@matrix:~$

    Quando teclamos o Ctrl + Z, o bash nos diz que o job 1 foi parado ([1]+ Stopped) e quando executamos "bg 1" ele nos diz que o comando voltou a ser executado, mas em bg (repare o sinal de "&" no final da linha): [1]+ cp -i arquivo1 arquivo2 &.

    Redirecionamento de saídas

    Muitos programas que executamos geram saídas no console, ou sejam, emitem mensagens para os usuários. Por exemplo, queremos achar quantos arquivos no nosso sistema tem "netscape" no nome:

    neo@matrix:~$ find / -name netscape
    /usr/lib/netscape
    /usr/lib/netscape/netscape
    /usr/lib/netscape/nethelp/netscape
    /usr/local/bin/netscape

    Agora se quisermos procurar quantos arquivos compactados com o gzip (extensão .gz) tem no nosso sistema para depois analisá-los e possivelmente apagar os repetidos ou inúteis, teremos uma lista muito grande. Aqui no meu sistema deu mais de 1000 arquivos. Então, seria útil podermos enviar as mensagens que vão para o console, para um arquivo. Assim, poderíamos analisá-lo depois de executar o comando. Isso é extremamente útil ao trabalharmos com shell script - enviar as saídas dos comandos para arquivos para depois analisá-las. Exemplificando:

    neo@matrix:~$ find / -name "*.gz" > lista.txt
    find: /home/vera: Permissão negada
    find: /home/pri: Permissão negada
    find: /root: Permissão negada
    neo@matrix:~$

    Notamos que nem tudo foi para o arquivo lista.txt. As mensagens de erro foram para o console.

    Isso porque existem dois tipos de saída: a saída padrão e a saída de erro.A saída padrão é a saída normal dos programas, que no caso acima, seria os arquivos encontrados. E a saída de erro, como o próprio nome diz, são os erro encontrados pelo programa durante sua execução, que devem ser informados ao usuário, como os erros de "permissão negada".

    E aí, como selecionar uma ou outra? É simples, apenas devemos indicar o "file descriptor" (fd) delas. Não vamos entrar em detalhes sobre o que é "descritor de arquivos" por fugir do nosso escopo e ser um pouco complicado, apenas temos que saber que o fd 1 corresponde a saída padrão e o fd 2 a saída de erro. Assim, no exemplo acima, para enviar os erro para o arquivo erros.txt e a saída padrão para o arquivo lista.txt, usaríamos:

    neo@matrix:~$ find / -name "*.gz" 1> lista.txt 2> erros.txt

    Ou seja, é só por o número da saída desejada antes do sinal de ">".

    Agora digamos que queremos ver o conteúdo do arquivo lista.txt. Podemos abrí-lo com um editor de textos ou usar o "cat". Optando pela última opção:

    neo@matrix:~$ cat lista.txt
    /home/neo/gkrellm-0.10.5.tar.gz
    /home/neo/linuxcall-interface-beta.tar.gz
    ...
    <<< mais de 1000 linhas
    neo@matrix:~$

    Temos um problema. O arquivo tem mais de 1000 linhas e não conseguimos vê-lo inteiro. Podemos redirecionar a saída do comando "cat" para o comando "more", que dá pausa entre as telas:

    neo@matrix:~$ cat lista.txt | more
    .........

    Veja que utilizamos o caractere "|", chamado "pipe". Não poderíamos ter utilizado o sinal de ">"? Não, o sinal de ">" é somente para enviar a saída para um ARQUIVO. Para enviar a saída de um comando para a entrada de outro, usamos o pipe.

    As vezes queremos que além da saída ir para um arquivo, ela também vá para a tela. Temos um programinha que faz isso. Ele chama-se "tee". Veja o exemplo a seguir:

    neo@matrix:~$ find / -name "*.gz" 2> erros.txt | tee lista.txt

    O que fizemos???Primeiro pegamos a saída de erro e enviamos para o arquivo erros.txt. O restante, ou seja, a saída padrão, estamos enviando para a entrada do comando tee (usando o pipe). O tee simplesmente pega o que ele recebe (através do pipe) e joga no arquivo lista.txt e na tela. Assim, além de gravarmos a saída num arquivo, podemos mostrar ao usuário o que está acontecendo. Isso é muito útil quando escrevemos alguns scripts.

    Resumindo: aprendemos que podemos redirecionar a saída padrão ou de erro de programa para um arquivo usando respectivamente "1>" ou "2>" ou também enviar a saída para a entrada de outro programa usando o pipe "|".

    Códigos de Escape

    Toda vez que executamos um programa em Unix, ele retorna um código de escape ao finalizar. Esse código reflete a condição em que o programa finalizou. Se ocorreu tudo certo e o programa terminou normalmente, ele retorna 0. Se ocorreu algum problema, o programa retorna um código diferente de 0, geralmente variando com o problema ocorrido.

    Esse código de retorno é extremamente importante em shell script, pois é assim que testamos se uma certa ação ocorreu bem ou teve problemas.Esse código é armazenado pelo bash numa variável chamada "?" (isso mesmo, somente o sinal de interrogação ;-)).

    Por exemplo, vamos executar um "ls" em um diretório que existe e ver o código de retorno:

    neo@matrix:~$ ls /boot
    System.map boot.0300 boot.b boot_message.txt chain.b config map os2_d.b
    neo@matrix:~$ echo $? 0
    neo@matrix:~$

    Ou seja, o "ls" foi executado normalmente, retornando 0. Agora vamos executá-lo num diretório que não existe:

    neo@matrix:~$ ls /diretorio_invalido
    /bin/ls: /diretorio_invalido: Arquivo ou diretório não encontrado
    neo@matrix:~$ echo $?
    1
    neo@matrix:~$

    Como esperado, obtemos o retorno de erro 1.

    Alguns programas tem muitos códigos de retorno. Por exemplo, os códigos de retorno do "pppd" vão até o 19. Assim é possível saber porque ele foi finalizado. Se você colocar uma senha errada no pppd e tentar conectar, ele vai terminar com o código 19.

    man pppd
    ...
    17 The PPP negotiation failed because serial loopback was detected.
    18 The init script failed (returned a non-zero exit status).
    19 We failed to authenticate ourselves to the peer.
    ...

    Um detalhe importante: quando executamos um programa em background, ele sempre retorna um código 0 para o shell, mesmo que durante sua execução ocorra algum problema. Assim, quando executamos um programa em bg, perdemos essa facilidade de testar como foi seu término.

    neo@matrix:~$ ls /diretorio_invalido &
    [1] 230
    neo@matrix:~$ /bin/ls: /diretorio_invalido: Arquivo ou diretório não encontrado

    [1]+ Exit 1 /bin/ls $LS_OPTIONS /diretorio_invalido
    neo@matrix:~$ echo $?
    0

    Como vemos, ao terminar, ele emite uma mensagem dizendo que finalizou com código 1 ([1]+ Exit 1) mas quando testamos a variável "?", o bash nos diz "0".

    Conclusão

    Como todos os programas tem que terminar com um código de retorno que tenha algum significado, nossos shell scripts também terão que finalizar indicando o que aconteceu, se ocorreu tudo bem ou se ouve erro. Mas isso discutiremos melhor mais pra frente.

    O importante aqui é saber que todos os programas terminam com um código de retorno, os quais usaremos nos nossos scripts para testar o término dos programas.
    Mesmo longe, eu estou perto. Guia do Hacker 4ever.
X
Working...
X