e
e
Book
Book
Adbeel Goes Filho
Fortaleza – Ceará Brasil Versão 2006.04.25Shell
Shell
Scripts
Scripts
ADBEEL GOES FILHO
VIRTVS
VIRTVS
Fortaleza 2006Shell
Shell
Scripts
Scripts
CopyFree (C) 2006 da VIRTVS Engenharia e Informática Ltda
Congregamos todos os esforços para fornecer informações de ampla qualidade, contudo, devido ao dinamismo da área de informática, os autores não assumem responsabilidade pelos resultados e usos das informações fornecidas. Recomentamos amplamente aos leitores testar as informações antes de sua efetiva utilização, ao tempo em que agradecemos antecipadamente por críticas e sugestões prestadas. Copyright (c) 2000, Adbeel Goes Filho. É garantida a permissão para copiar, distribuir e/ou modificar este documento sob os termos da GNU Free Documentation License, versão 1.1 ou qualquer outra versão posterior publicada pela Free Software Foundation; sem obrigatoriedade de Seções Invariantes na abertura e ao final dos textos. Uma copia da licença deve ser incluída na seção intitulada GNU Free Documentation License. Copyright (c) 2000, Adbeel Goes Filho. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; with the Invariant Sections being LIST THEIR TITLES, with the FrontCover Texts being LIST, and with the BackCover Texts being LIST. A copy of the license is included in the section entitled "GNU Free Documentation License". Este trabalho foi editado e composto eletronicamente utilizando somente ferramentes livres: Conhecimentos necessários para a leitura deste trabalho:Entendimento básico de sistemas operacionais, Comandos básicos de Unix, Linux, Solaris, FreeBSD ou outro sistema operacional com base Unix, Linguagem de programação, Edição eletrônica de textos. Editor Responsável Satis Diagramação e Produção Virtvs VIRTVS Engenharia e Informática Rua Cel. Ribeiro da Silva, 391. CEP 60.325210. Monte Castelo. Fortaleza – CE. Telefone: +55 (85) 32833124 www.virtvs.com.br
SOBRE O AUTOR Adbeel Goes Filho
adbeel@virtvs.com.br adbeel@dnocs.gov.br adbeel@terra.com.br
Engenheiro Civil pela Universidade Federal do Ceará (UFC). Especialista em Ciência da Computação pela Universidade Federal do Ceará (UFC). Mestre em Ciência da Computação pela Universidade Federal do Ceará (UFC). Especialista em Matemática Computacional e Otimização de Sistemas. Doutorando em Engenharia Civil – Recursos Hídricos (UFC) Acadêmico de Administração de Empresas pela Universidade Estadual do Ceará (UECE). Professor do Curso de Graduação em Informática da Universidade de Fortaleza (UNIFOR). Coordenador de Gestão Estratégica do Departamento Nacional de Obras Contra as Secas (DNOCS). Diretor de Engenharia e Informática da VIRTVS Engenharia e Informática Ltda Consultor nas áreas de engenharia civil e informática em empresas e instituições públicas. Consultor na área de custos e acompanhamento de projetos de engenharia civil. Consultor da PERITUS Projetos e Pesquisas Ltda, na área de organização, projetos e informática. Exprofessor dos cursos de Processamento de Dados, Engenharia Civil, Agronomia, Engenharia e Alimentos, Geologia, Matemática e Estatistica da Universidade Federal do Ceará (UFC). Exprofessor do Curso de Bacharelado em Computação da Faculdade Lourenço Filho. Exdiretor de engenharia e informática da Rhodes Engenharia e Informática Ltda. ExAnalista de Sistemas da Fundação Cearense de Meteorologia (FUNCEME).
AGRADECIMENTOS VIRTVS Engenharia e Informática Ltda Departamento Nacional de Obras Contra as Secas – DNOCS Universidade Federal do Ceará – UFC Universidade de Fortaleza – UNIFOR Faculdade Lourenço Filho FLF AGRADECIMENTOS ESPECIAIS Aos meus pais Elsie Studart e Adbeel Goes de Oliveira Aos meus avós (in memoriam) Angelina Goes de Oliveira e Luis Rodrigues de Oliveira Olga Sales Lopes Gurgel e Benjamim Studart Gurgel A minha esposa Cristine Studart de Santana A meu grande mestre Prof. Dr. Gerardo Valdisio Rodrigues Viana Ao meu orientador acadêmico e de vida Prof. Dr. Clécio Fontelles Thomaz Ao meu orientador e incentivador Prof. Dr. Nilson Campos Aos meus grandes mestres: Antônio Gouveia Neto Afrodisio Durval Gondim Pamplona Amaury Aragão Araújo Genésio Martins de Araújo Suetônio Mota Vicente de Paula Barbosa Vieira A todos os outros que, pelo esquecimento, tipico da natureza humana, deixamos de citar.
Marcas Registradas
Durante este trabalho aparecem várias marcas registradas, contudo, o autor declara estar utilizando tais nomes apenas para fins editorais, em benefício exclusivo da marca registrada, sem a mínima intenção de infrigir regras de sua utilização.
Sumário
Capitulo 1. Introdução...10 1.O Shell ...10 2.O que são os shell scripts ? ...12 3.Definições ...14 4.Variáveis ...14 5.Formato dos Arquivos de Shell Script ...22 6.Exercicios...34 Capitulo 2. Execução de Programas...36 7.Execução em foreground e background ...36 8.Redirecionamento...37 9.Metacaracteres e Wildcards...40 10.Sequências de Escape ANSI...44 11.Códigos de Escape ...49 12.Conclusões...50 13.Exercicios...51 Capitulo 3. Comandos Condicionais...52 Capitulo 4. Comandos de Repetição...62 14.while...62 15.for ...63 16.until...66 17.case ...66 18.break e continue...67 19.Redirecionando loops...69 20.select ...75 21.Funções...78 22.Tornando seu script amigável...87 23.dialog...89 Capitulo 5. Comandos Avançados...94 1.cut...94 2.wc...98 3.tee...98 4.sort...99 5.grep...100 6.sed...106 Capitulo 6. Bibliografia...113 Capitulo 7. Apêndice A – Endereços Internet...114 Capitulo 8. Anexos...115 1.Exemplos...116 2.Laboratórios...132 3.Exercicios...140 5.GNU Free Documentation License...143Abreviações Utilizadas
*IX Sistema operacional fundamentado em Unix LP Linguagem de programação
SO Sistema Operacional
Capitulo 1.
Capitulo 1.
Introdução
Introdução
1.
1.
O Shell
O Shell
Shell, ou interpretador de comandos, é o programa disparado logo após o login responsável por "pegar" os comandos do usuário, interpretálos e executar uma determinada ação. Estas ações são subrotinas conhecidas pelo nome de system calls. Por exemplo, quando você
escreve no console "ls" e pressiona <enter>, o shell lê essa string e verifica se existe algum comando interno (embutido no próprio shell, também chamado de intrínseco) com esse nome. Se houver, ele executa esse comando interno. Caso contrário, ele vai procurar no PATH por algum programa que tenha esse nome. Se encontrar, ele executa esse programa, caso contrário, ele retorna uma mensagem de erro. Para cada terminal ou console aberto, existe um shell sendo executado. Quando você entra no seu Linux, ele apresenta o login, para digitar o usuário e a senha. Ao digitar um par usuário/senha correto, o Linux abre automaticamente um shell, que vai ficar esperando seus comandos. Funcionando como uma ponte, o Shell é a ligação entre o usuário e o kernel. O kernel é quem acessa o hardware da máquina, como disco rígido, placa de vídeo e modem. Por exemplo, para o usuário acessar um arquivo qualquer, toda esta hierarquia é seguida: Antes de Começar Se você está acessando o sistema como usuário administrador (root), saia e entre como um usuário normal. É muito perigoso estudar Shell usando o superusuário, você pode danificar o sistema com um comando errado. Veja o exemplo abaixo: Welcome to Linux Slackware 7.1 kernel 2.2.16. virtvs login: eu Password: USUÁRIO > SHELL > KERNEL > HARDWARE
Linux 2.2.16. Last login: Mon Sep 25 10:41:12 0300 2000 on tty1. No mail. virtvs@mucuripe:~$ Essa última linha é o shell. Se você digitar o comando "ps", verá que um dos programas rodando é o seu shell . O comando “ps” lista os processos em : virtvs@mucuripe:~$ ps PID TTY TIME CMD 164 tty2 00:00:00 bash 213 tty2 00:00:00 ps virtvs@mucuripe:~$ Ou seja, o shell utilizado nesse console é o bash, que está rodando com PID 164. Existem diversos tipos de shell: bash, csh, ksh, ash, etc. Por exemplo, o AIX/6000 possui 5 tipos de shell disponíveis: korn shell (ksh), bourne shell (bsh, sh), C shell (csh), trusted shell (tsh), restricted shell (rsh). O default para este sistema é o ksh. O mais utilizado atualmente é o bash (GNU BourneAgain SHell). Por isso o tomaremos como referência. Resumindo essa seção, é importante saber que para cada terminal ou console aberto, temse um shell rodando. Assim, se você tem 3 xterms abertos na interface gráfica, vai ter um shell para cada xterm. Ao executar o shell script, o shell atual (no qual você deu o comando) abre um novo shell para executar o script. Assim, os scripts são executados em um shell próprio (a menos que se especifique, ao chamar o script, para executálo no shell atual). Isso será importante quando formos tratar de variáveis de ambiente. O uso de alias Alias é um novo nome, ou apelido, para o comando. Pode ser usado para abreviar longas linhas de comando ou fazer com que comandos comportemse diferente da execução padrão. Sintaxe: alias [nome[=string]] Exemplo: alias cls=clear alias ls='ls logt' alias dir=ls
2.
2.
O que são os
O que são os
shell
shell
scripts ?
scripts ?
Shell scripts são conjuntos de comandos armazenados em um arquivo texto que são executados seqüencialmente. Nesta primeira parte, faremos uma introdução sobre o shell, o formato desses arquivos e variáveis de ambiente. Shell pode ser standard ou restrito, na verdade é um comando que possibilita gerar textos com lógica de programação. É muito utilizado para montagem de ambientes de login e abertura de novos processos que indicam nova seção. Existe vários tipos de shells, a mais utilizada é a sh, que é um link da bash, ou seja /bin/sh é link de /bin/bash Detalhes importantes Qualquer shellscript criado necessita na "primeira linha" de indicar onde se encontra o shell interpretador, ou seja o destino, que por padrão é #!/bin/sh, porém pode ter casos de se localizar em outro diretório. Também devo dizer que todo shellscript deve ter permissão para obter a execução. Caso não seja informada esta primeira linhx o shell usará a default do sistema. Sintaxe : $chmod a+x shellscript Para colocar comentários assim como no PERL, utilize o # (chamado culturalmente de sustenido) O Primeiro Shell Script O primeiro Shell Script a fazer será o "sistema" do exemplo anterior, de simplesmente juntar três comandos num mesmo script. Passos Para Criar um Shell Script 1. Escolher um nome para o script Já temos um nome: sistema. Use apenas letras minúsculas e evite acentos, símbolos e espaço em branco 2. Escolher o diretório onde colocar o script Para que o script possa ser executado de qualquer parte do sistema, movao para um diretório que esteja no seu PATH. Para ver quais são estes diretórios, use o comando: echo $PATH Se não tiver permissão de mover para um diretório do PATH, deixeo dentro de seu HOME 3. Criar o arquivo e colocar nele os comandos
Use o VI ou outro editor de textos de sua preferência para colocar todos os comandos dentro do arquivo. 4. Colocar a chamada do Shell na primeira linha A primeira linha do script deve ser: #!/bin/bash Para que ao ser executado, o sistema saiba que é o Shell quem irá interpretar estes comandos. 5. Tornar o script um arquivo executável Use o seguinte comando para que seu script seja reconhecido pelo sistema como um comando executável: chmod +x sistema Problemas na Execução do Script "Comando não encontrado" O Shell não encontrou o seu script. Verifique se o comando que você está chamando tem exatamente o mesmo nome do seu script. Lembrese que no Linux as letras maiúsculas e minúsculas são diferentes, então o comando "SISTEMA" é diferente do comando "sistema". Caso o nome esteja correto, verifique se ele está no PATH do sistema. O comando "echo $PATH" mostra quais são os diretórios conhecidos, mova seu script para dentro de um deles, ou chameo passando o caminho completo. Se o script estiver no diretório corrente, chameo com um "./" na frente, assim: $./sistema Caso contrário, especifique o caminho completo desde o diretório raiz: $/tmp/scripts/sistema "Permissão Negada" O Shell encontrou seu script, mas ele não é executável. Use o comando "chmod +x seuscript" para tornálo um arquivo executável. "Erro de Sintaxe" O Shell encontrou e executou seu script, porém ele tem erros. Um script só é executado quando sua sintaxe está 100% correta. Verifique os seus comandos, geralmente o erro é algum IF ou aspas que foram abertos e não foram fechados. A própria mensagem informa o número da linha onde o erro foi encontrado.
3.
3.
Definições
Definições
Branco e TAB ou espaço são a mesma coisa. Um nome é uma sequência de letras, digitos ou underscores começando com uma letra ou underscore. Um parâmetro é um nome um digito ou algum desses caracteres: *, #, ?, , $, e !. Comando : é uma sequência de não brancos separados por brancos. A primeira sequência ou argumento é o argumento 0. Pipeline : é uma sequência de um ou mais comandos separados por | (ou, para compatibilidade histórica, pelo ^). A função de uma pipeline é sincronizar a entrada ou saida padrão para um arquivo do tipo FIFO.
Uma lista : é uma sequência de pipelines separadas por;. &, &&, or ||, e opcionalmente, terminada por ; ou &. Exemplos de comandos do shell: for name [ in word ... ] do list done case word in [ pattern [ | pattern ] ...) list ;; ] ... esac if list then list [ else list then list ] ... [ else list ] fi while list do list done
4.
4.
Variáveis
Variáveis
Uma variável é onde o shell armazena determinados valores para utilização posterior. São áreas de memória onde podem ser armazenados dados. Estes dados podem ser números, textos, listas de arquivos e até mesmo resultados da saida de comandos que podem ser utilizados posteriormente. Existem duas categorias de variáveis que podemos definir no ambiente Unix:1. Variáveis locais – disponíveis somente para o Shell corrente, não sendo acessadas pelos subprocessos;
2. Variáveis ambientais ou globais – disponíveis tanto para o Shell corrente como para os subprocessos que venham a usar o conteúdo das variáveis definidas. Para transformar uma variável com escopo global utilize o comando export. Exemplo: export <variável> Para a visualização das variáveis locais, usase o comando set. Para verificar quais variáveis estão exportadas, usase o comando env. Toda variável possui um nome e um valor associado a ela, podendo ser este último vazio. Para listar as variáveis atualmente definidas no shell digite o comando set. Para se definir uma variável, basta utilizar a síntaxe (Sem espaço ao redor do =): nome_da_variável=conteúdo Por exemplo, queremos definir uma variável chamada "cor" com o valor de "azul":
virtvs@mucuripe:~$ cor=azul Para utilizar o valor de uma variável, é só colocar um sinal de "$" seguido do nome da variável o shell automaticamente substitui pelo valor da variável: virtvs@mucuripe:~$ echo cor cor virtvs@mucuripe:~$ echo $cor azul Em alguns casos, é aconselhável colocar o nome da variável entre chaves {}. Por exemplo, se quero imprimir "azulescuro", como faria ? Simplesmente echo $corescuro ? Não funcionaria, pois o bash vai procurar uma variável de nome "corescuro". Portanto, temos que colocar o nome "cor" entre chaves para delimitar o nome da variável: virtvs@mucuripe:~$ echo ${cor}escuro azulescuro Algumas variáveis já são predefinidas no shell, como o PATH, que, como foi dito antes, armazena o caminho dos programas. Por exemplo, a minha variável PATH contém: virtvs@mucuripe:~$ echo $PATH /usr/local/bin:/usr/bin: /bin: /usr/X11R6/bin: /usr/openwin/bin:/usr/games: /opt/kde/bin: /usr/share/texmf/bin: /etc/script ou seja, quando digito um comando, como "ls", o shell vai começar a procurálo em /usr/local/bin, se não encontrálo, vai procurar em /usr/bin e assim por diante. Repare que os diretórios são separados por um sinal de dois pontos (:).
É importante destacar que o shell possui várias variáveis prédefinidas, ou seja, que possuem um significado especial para ele, entre elas: PATH, PWD, PS1, PS2, USER e UID. Assim, quando iniciamos um novo shell (ao executar o nosso script), essas variáveis especiais são "herdadas" do shell pai (o que executou o shell filho). Outras variáveis definidas pelo usuário, como a variável "cor" não são passadas do shell pai para o filho. Quando o script terminar, o seu shell (shell filho) simplesmente desaparece e com ele também as suas variáveis, liberando o espaço ocupado na memória.
Para tornar uma variável imune à alteração ou deleção, devese usar o comando readonly Variáveis somente leitura não podem ser apagadas. Elas somente deixarão de existir no momento em que for efetuado o logout da sessão de terminal, ou se o programa que criou a variável for encerrado, exceto no caso de o Shellscript estar rodando na mesma instância de interpretador que iniciou a execução do scriptShell. readonly nome Para apagar uma variável, use o comando unset:
unset nome Variáveis Array Também conhecidas como vetores. Este tipo de variável serve para armazenar vários valores sob um nome e um índice. A maneira de declarar variáveis array é a seguinte: NomeDaVariavel[Indice]=Valor sendo que Indice deve ser necessariamente um valor inteiro. Imaginemos que Maria queira armazenar uma lista de suas frutas favoritas em uma variável array. Para isso ela faria o seguinte: $ FRUTA[0]=goiaba $ FRUTA[1]=manga $ FRUTA[2]=pera $ FRUTA[3]=laranja Supondo que ele colocou esta lista em ordem decrescente de gosto, para sabermos qual é a sua fruta favorita basta digitarmos: $ echo ${FRUTA[0]}
Se colocarmos $FRUTA[0] e shell exibirá goiaba[0] (goiaba concatenado com [0]. Desta forma notase a necessidade do uso de {} Agora vejamos uma coisa interessante. Se eu declarar uma variável assim: $FRUTA=goiaba e depois quiser fazer um array com o nome FRUTA eu posso fazer assim: $ FRUTA[1]=manga Desta maneira 'goiaba' passa a ser armazenada em FRUTA[0] Outra coisa interessante é que podemos declarar um array inteiro numa única linha de comando. Para isto usamos a sintaxe: NomeDoArray=(valor1 valor2 ... valorn) Desta maneira Maria economizaria teclado digitando isto: $FRUTA=(goiaba manga pera laranja)
E para vermos toda a lista de uma vez só, podemos usar o seguinte comando: $ echo ${FRUTA[*]}
Existem várias outras especificações para arrays, aqui é só o básico. E se você precisar usar arrays de maneira mais complexa que isso procure a documentação oficial do bash.
Ambiente do usuário
O ambiente do usuário descreve a sessão para o sistema, contendo as seguintes informações, geralmente armazenadas em variáveis de ambiente: . Caminho para o diretório home HOME; . Para onde enviar seu correio eletrônico MAIL; . Fuso horário local TZ; . Com que nome você se logou LOGNAME; . Onde seu shell pesquisará os comandos PATH; . Seu tipo de terminal TERM; . Outras definições necessárias. A variável PS1 Esta é a "Prompt String 1" ou "Primary Prompt String". Nada mais é do que o prompt que nos mostra que o shell está esperando um comando. Quando você muda PS1 você muda a aparência do prompt. Na minha máquina o padrão é '\u@\h:\w\$ ' onde \u significa o nome do usuário, \h significa o nome do host e \w é o diretório atual, o que dá a seguinte aparência: meleu@meleu:/usr/doc/LinuxHOWTOs$ Veja algumas possibilidades (Verifique mais no manual do bash): \d mostra a data atual \h mostra o hostname \s o nome do shell \t a hora atual (no estilo 24 horas) \T a hora atual (no estilo 12 horas) \u nome do usuário que está usando o shell \w nome do diretório atual (caminho todo) \W nome do diretório atual (somente o nome do diretório) Se você estiver afim de ter a impressão de que está no shell do root basta trocar o '$' por '#' Para aprender a fazer um monte de gracinhas com o PS1 dê uma lida no BashPromptHOWTO A variável PS2
Esta é a "Secondary Prompt String". É usada quando um comando usa mais de uma linha. Por exemplo: $ echo m\ > e\ > l\ > e\ > u meleu $ echo 'm > e > l > e > u' m e l e u Este sinal '> ' (maiorespaço) é o PS2. Você pode usar os mesmos caracteres especiais que o PS1 usa. A variável MAIL Nada mais é do que o arquivo onde são guardados seus emails. Aqui na minha máquina eu uso o sendmail como servidor de email, portanto: meleu@meleu:~$ echo $MAIL /var/spool/mail/meleu porém se estivesse usando qmail seria: meleu@meleu:~$ echo $MAIL /home/meleu/Mailbox A variável SHLVL Esta variável armazena quantos shells você executou a partir da primeira shell. Imagine que você está usando o bash e executou o bash de novo, nesta situação o seu SHLVL vale 2. Veja isto: $ echo $SHLVL 1 $ bash # estou executando o bash a partir do bash $ echo $SHLVL
2 $ exit # saí do segundo bash exit $ echo $SHLVL 1 Quando você inicializa scripts a partir do comando "source" o script é executado no shell pai, portanto se tiver um "exit" no script você vai executar um logoff. É aí que está a utilidade da variável SHLVL. Quando você está no shell primário o valor de SHLVL é 1. Então você pode, através de um "if" por exemplo, executar o "exit" só se SHLVL for diferente de 1. A variável PROMPT_COMMAND Esta é bem interessante. Ela armazena um comando que será executado toda hora que o prompt é exibido. Veja: $ PROMPT_COMMAND="date +%T" 19:24:13 $ cd 19:24:17 $ ls GNUstep/ bons.txt pratica/ teste worldwritable.txt Mail/ hacking/ progs/ txts/ 19:24:19 $ 19:24:32 $ # isso eh uma linha sem nenhum comando 19:24:49 $ Esta variável é útil quando queremos brincar com o prompt, para aprender mais sobre isso leia o BashPromptHOWTO (v. 10. Referências). A variável IFS O shell usa esta variável para dividir uma string em palavras separadas. Normalmente o IFS é um espaço, uma tabulação (Tab) e um caractere nova linha (\n). Desta maneira: isto eh uma string são quatro palavras, pois IFS é um espaço e as palavras estão separadas por espaço. Agora se eu mudar IFS para um ':' desta maneira: IFS=':' então a string:
isto:eh:uma:string conterá quatro palavras. Isto é útil para casos como neste exemplo: #!/bin/bash IFS=':' for item in $PATH ; do echo $item done Se IFS for uma variável nula (vazia), tudo será considerado uma única palavra. Por exemplo: se o IFS for nulo, toda essa linha será considerada uma única palavra A variável RANDOM Quando você exibe esta variável ("echo $RANDOM") é exibido um número aleatório entre 0 e 32767. #!/bin/bash NUM="98$(echo $RANDOM)0" CONT=$(echo n $NUM | wc c) # quantos digitos tem? while [ $CONT lt 8 ]; do # se nao tiver 8 digitos acrescenta 0's NUM=${NUM}0 CONT=$(echo n $NUM | wc c) done echo $NUM Outras Variáveis Outras variáveis que são muito usadas: MAILCHECK ; HISTFILE ; HOSTNAME ; LS_OPTIONS ; LS_COLOR ; MANPATH ; SHELL ; TERM ; USER ; PS3 .
Estas são as mais utilizadas, porém existem muitas outras. Para ver quais são as variáveis definidas no momento basta entrar com o comando "set". E para ver apenas as variáveis de ambiente use "env". Olhe a man page do bash na seção "Shell Variables" para mais detalhes. Configurando variáveis do Shell nome=conteúdo Não deve haver espaço antes ou depois do sinal de igual. Isso assegura que a atribuição seja feita corretamente, não sendo interpretada com o um comando com argumentos separados por espaço. Poderemos tambem acessar substrings em variaveis na forma
#a=”13/05/2004” #b=${a:6:4} #echo $b #2004 A variável PATH Armazena a relação de diretório, usada pelo Shell para pesquisa de comandos. Os diretórios a serem pesquisados devem estar separados por (:). Lembrese que os nomes de variáveis são sensíveis ao contexto, ou seja PATH não é igual a PaTh. Exemplo: export PATH=/usr/bin:/usr/sbin:. Exercícios 1. Crie um alias limpatela que execute o comando clear. 2. Mude o prompt do sistema para que apareça: <usuário>@<diretório corrente>$ 3. Coloque o alias criado anteriormente no seu shell. 4. Elabore um shellscript para gerar 10 números aleatórios.
5.
5.
Formato dos Arquivos de Shell Script
Formato dos Arquivos de Shell Script
A primeira linha de todo shellscript deve começar com algo do tipo (Se não colocar é assumido o shell padrão): #!/bin/bash a qual indica com qual shell deverá ser executado o script. Nesse exemplo, estamos falando para o shell atual executar o script com o shell /bin/bash. Se quisermos que o nosso script seja executado com o shell csh, devemos colocar nessa primeira linha: #!/bin/cshComo usaremos o bash como nosso shell de referência, todas as linhas dos nossos scripts começarão com #!/bin/bash Digamos que você executa freqüentemente o comando: find / name file print que procura na raiz (/) por um arquivo de nome "file". Só que é incômodo ficar digitando esse comando toda vez que se quer procurar um arquivo. Então vamos criar um shell script que contenha esse comando. Vamos chamar esse shell script de "procura". Seu conteúdo fica assim: #!/bin/bash find / name file print Tornemos agora o arquivo executável: chmod 755 ./procura . Porém, ao tentar executar o nosso script, teremos um problema. ./procura Este script irá procurar por um arquivo chamado "file". Como especificar qual arquivo queremos procurar ? Seria ideal executarmos o nosso script seguido do nome do arquivo que queremos procurar. Por exemplo, queremos saber onde está o arquivo "netscape": ./procura netscape É ai que entram as "variáveis de parâmetro". Vamos substituir no nosso script a linha find / name file print por find / name $1 print Quando o bash lê a variável "$1", ele a substitui pelo primeiro parâmetro passado na linha de comando para o nosso script. Então, se executamos ./procura netscape , a variável "$1" será substituída por "netscape", como a gente queria. Repare que a variável "$2" conteria o segundo parâmetro passado para o script e assim por diante.
Esse é o essencial do shell script: poder automatizar a execução de programas e comandos como se estivessem sendo digitados diretamente no console ou terminal. 1. Capacidades de substituição do Shell Uma característica interessanto no shell é a capacidade de podermos manipular textos, números e até saída de comandos através de variáveis. Existem 3 tipos de substituição no Shell: 1. Substituição de variáveis \ parâmetros; 2. Substituição de comandos; 3. Substituição do til; Substituição de variáveis \ parâmetros Cada variável tem um valor associado a ela. Quando o nome de uma variável for precedido por uma sinal de $ (dólar), o Shell substituirá o parâmetro pelo conteúdo da variável. Este procedimento é conhecido com Substituição de Variável. Uma das maneiras de exibir o conteúdo de uma variável é usando o comando echo. Existem dois tipos de parâmetros: posicional e o de palavra chave. Se o parâmetro é um digito, então é posicional. Palavras chave (também conhecida como variáveis) podem ter seus valores escritos. ${variavel:string} Se "variavel" não tiver sido definida ou for vazia será substituída por "string". O valor da variável não é alterado. Veja este exemplo: $ echo ${URL:"http://unsekurity.virtualave.net"} http://unsekurity.virtualave.net $ echo $URL # observe que URL nao foi alterado ${variavel:=string} Se "variavel" não estiver sido definida ou for vazia, receberá "string". Exemplo: $ echo ${WWW:="http://meleu.da.ru"} http://meleu.da.ru $ echo $WWW http://meleu.da.ru ${variavel:?string} Se "variavel" não estiver sido definido ou for vazia, "string" será escrito em stderr (saída de erro padrão). O valor da variável não é alterado. Veja um exemplo:
$ echo ${EDITOR:?"Nenhum editor de texto"} bash: EDITOR: Nenhum editor de texto
$ echo $EDITOR
${variavel:+string}
Se "variavel" estiver definida, será substituída por "string" mas seu valor não será alterado. Exemplo: $ echo ${BROWSER:+"BROWSER definido como \"$BROWSER\""} BROWSER definido como "links" Variáveis SomenteLeitura Como sabemos as variáveis podem ter seu valor modificado pelo usuário, mas se nós quisermos variáveis que NÃO possam ter seus valores alterados basta declararmos tal variável como somenteleitura. Para tornar uma variável readonly podemos usar o comando "readonly" ou então "declare r". Veja os exemplos a seguir, ambos possuem o mesmo resultado: $ readonly NOME="Meleu Zord" $ echo $NOME Meleu Zord $ declare r NOME="Meleu Zord" $ echo $NOME Meleu Zord $ NOME=Fulano bash: NOME: readonly variable $ echo $NOME Meleu Zord Um bom uso deste tipo de variável é para garantir que variáveis importantes de um determinado script não possam ser sobregravadas, evitando assim algum resultado crítico. O comando "readonly" quando usado sem parâmetros (ou o comando "declare" apenas com o parâmetro "r") nos mostra todas as variáveis declaradas como somenteleitura. No exemplo a seguir se for usado "declare r" no lugar de "readonly" teríamos a mesma saída. $ readonly declare ar BASH_VERSINFO='([0]="2" [1]="05" [2]="0" [3]="1" [4]="release" [5]="i386slackwarelinuxgnu")' declare ir EUID="1005" declare ir PPID="1"
declare r
SHELLOPTS="braceexpand:hashall:histexpand:monitor:ignoreeof:interactivecomments:emacs" declare ir UID="1005"
Existem variáveis somenteleitura que são inicializadas pelo shell, como USER, UID. TODAS as variáveis readonly uma vez declaradas não podem ser "unsetadas" ou ter seus valores modificados. O único meio de apagar as variáveis readonly declaradas pelo usuário é saindo do shell (logout). Parâmetros Podemos passar parâmetros para o shellscript assim como na maioria dos programas. Os parâmetros são variáveis, digamos, especiais. Para começar elas não obedecem as regras de nomeclatura de variáveis, pois elas usam números; e também nós não podemos mudar o valor destas variáveis pelas vias "tradicionais", para mudar o valor destas nós temos que contar com a ajuda do shift e/ou do set (como veremos adiante). Veja esta relação: $0 é o nome do shellscript (parâmetro zero); $1 a $9 $1 é o primeiro parâmetro, $9 o nono, e assim por diante; ${10}, ${11}.. quando o número do parâmetro possui mais de um dígito é necessário o uso das chaves; $* todos os parâmetros em uma única string (exceto o $0) $@ todos os parâmetros, cada um em strings separadas (exceto $0) $# número de parâmetros (sem contar com o $0). $? valor de retorno do último comando (explicado mais adiante); $$ PID do script; $! PID do último comando iniciado com &
Exemplo: #!/bin/bash # # "basename" serve para eliminar o caminho do arquivo e mostrar # somente o último nome dele. Neste caso: parametros.sh echo "Nome do script: `basename $0`" echo "Número total de parâmetros: $#" echo "Primeiro parâmetro: $1" echo "Segundo parâmetro: $2" echo "Décimo quinto parâmetro: ${15}" echo "Todos os parâmetros: $*" $ ./parametros.sh a b c d e f g h i j l m n o p q r s t u v x z Nome do script: parametros.sh Número total de parâmetros: 23 Primeiro parâmetro: a Segundo parâmetro: b Décimo quinto parâmetro: p Todos os parâmetros: a b c d e f g h i j l m n o p q r s t u v x z Se você não entendeu direito a diferença entre o $* e o $@, então dê uma olhada no seguinte script (se não entendêlo tudo bem, siga em frente e quando aprender sobre o "if" e o "for" leiao novamente): Exemplo: #!/bin/bash # Ao executar este script entre alguns parametros. Ex.: # [prompt]$ ./testargs.sh um dois tres quatro if [ z "$1" ]; then echo "Uso: `basename $0` argumento1 argumento2 etc." exit 1 fi echo echo "Listando argumentos com \"\$*\":" num=1 for arg in "$*"; do echo "Arg #$num = $arg" num=$[ $num + 1 ] done
# Conclusão: $* mostra todos os argumentos como uma única string echo echo "Listando argumentos com \"\$@\":" num=1 for arg in "$@"; do echo "Arg #$num = $arg" num=$[ $num + 1 ] done # Conclusão: $@ mostra cada argumento em strings separadas echo shift O bash possui um comando embutido que lida com parâmetros, o shift. Quando você usa o shift sai o primeiro parâmetro da lista e o segundo vai para $1 o terceiro vai para $2, e assim por diante. Você pode ainda especificar quantas "casas" você quer que os parâmetros "andem" à esquerda através de "shift n" onde 'n' é o número de casas, mas se o número de casas que ele deve andar for maior que o número de parâmetros o shift não é executado. Veja este exemplo: #!/bin/bash echo "$#: $*" echo e "executando \"shift\"" shift echo "$#: $*" echo e "executando \"shift 5\"" shift 5 echo "$#: $*" echo e "executando \"shift 7\"" shift 7 echo "$#: $*" $ ./shiftexemplo.sh 1 2 3 4 5 6 7 8 9 0 10: 1 2 3 4 5 6 7 8 9 0 executando "shift" 9: 2 3 4 5 6 7 8 9 0 executando "shift 5" 4: 7 8 9 0 executando "shift 7" 4: 7 8 9 0 Os valores que saem são perdidos. Use com atenção!
set (para editar parâmetros)
O que vou passar neste tópico não é sobre como usar "todo o poder do comando set", e sim como usar set especificamente para editar parâmetros. Não tem nenhum segredo! Veja este exemplo: set um dois tres Isso fará com que $1 seja 'um', $2 seja 'dois', $3 seja 'tres' e só! Não existirá $4, $5, etc. mesmo que eles tenham sido usados. Veja um exemplo de script: #!/bin/bash echo "Os $# parâmetros passados inicialmente foram: $@" echo echo "e agora eu vou alterálos!" echo "como eu sou mau... (huahuahau risada diabólica huahuahuha)" echo set um dois tres echo "Os $# novos parâmetros agora são: $@" echo Não interessa quantos parâmetros você passar para este script, no final você só terá $1, $2 e $3 valendo 'um', 'dois' e 'tres', respectivamente. Quoting Os caracteres abaixo tem um modo especial de tratar o shell : ; & ( ) | ^ < > newline space tab #
∙ caracter deve ser cotado pela precedência com um \. O par \newline é ignorado. Todos os caracteres fechados entre o par de acentos (‘), exceto aspas simples são cotadas. ∙ Um & no final do comando indica que este irá ser executado em background. O shell mostra o número do processo gerado. Para que você não perca este processo ao terminar seu shell, execute seu comando assim: $ nohup comando argv1 argv2 ... argvn& Exemplos: echo $PATH /usr/bin:/usr/local/bin
arquivo=/home/morro.txt more $arquivo txt1=Casa txt2=Mae txt3=Joana echo ${txt1}da$txt2$txt3 Observe que no último exemplo foram usadas as chaves para circundar o nome da variável, senão o Shell poderia interpretar a variável como txt1da, o que seria o nome da variável diferente de txt1, caso as chaves não fossem usadas, gerando mensagem de erro de parâmetro não definido, pois nesse caso a variável txt1da não existiria. Substituição de comando A substituição de comando é usada para substituir um comando por seu resultado dentro da mesma linha de comando. Isto será útil quando for necessário armazenar a saída de um comando em uma variável ou passar essa mesma saída para outro comando. A sintaxe utilizada é: $(comando) ou `comando` A substituição de comando permite que você capture o resultado de um comando e utilizeo como um argumento para outro comando ou armazene sua saída em uma variável. Exemplo: dir_atual=$(pwd) cp $(ls *.txt) /home/user1/backup Substituição do ~ (til) A substituição do til é executada de acordo com as seguintes regras: 1. Um til sozinho ou em frente a uma barra é substituido pelo conteúdo da variável HOME. Exemplo: HOME=/home/user3 echo ~ 2. Um til seguido do sinal de + é substituído pelo valor da variável PWD. 3. Um til seguido de – será substituiído pelo valor da variável OLDPWD. Exemplo: echo ~ ls 1F ~/file1 ls – logt ~+/poodle ls ~
Prompting
Quando usado interativamente, o prompt do shell é o valor da variável PS1 antes da leitura do comando. Se todo tempo uma linha deve ser digitada e uma nova linha teclada para completar o comando, então um segundo prompt é mostrado.
Input / Output
Antes de um comando ser executado, sua entrada e saida pode ser redirecionada usando as notações interpretadas pelo shell. < word Usando word como entrada padrão > word Usando word como saida padrão >> word Idem ao >, so que neste caso se word já existe não sobrepõe, faz o append. <&digit Uso associado a um descritor de arquivo como entrada padrão. Similar pela saida padrão usando >&digit. Note que digit precisa ser de um tamanho entre 0 a 9. Exemplo: ... 2>&1 Arquivo associado ao descritor 2 com o arquivo corrente associado com o descritor do arquivo 1. Note que o redirecionamento de I/O é necessário se você quer sincronia com stdout e stderr para o mesmo arquivo. Esta opção é bastante usado para se configurar impressoras ou dispositivos seriais. Conceito de Sinais Um sinal é u m flag transmitido para um processo quando certos eventos ocorrem. Os sinais mais conhecidos em ambiente *IX são: NULL Saida do Shell ( ^D ou exit ) HUP Hungup – enviado para processos em retaguarda no logout INT Interrupção ( ^C ) QUIT Quit ( ^\ ) gera arquivo core KILL Morte certa ( Não pode ser capturado ou ignorado ) TERM Terminação por software O comando kill transmite um sinal explícito para um ou mais processos. Diite kill l para obter uma lista de sinais disponíveis no SO. O que é um TRAP ? Um trap é uma maneira de capturar sinais transmitidos a um processo e de executar alguma ação baseada no tipo de sinal que foi recebido. A trap simplesmente espera por sinais enviados ao Shell, identificaos e então, executa
a ação associada. Uma trap pode ser definida para a remoção de arquivos temporários no término de um programa ou pode definir sinais que devam ser ignorados durante um segmento sensível na execução do programa. O comando trap O comando trap pode ser usado em programas Shell para capturar um sinal antes que ele possa abortar um processo e executar alguma ação adicional ou alternativa. Os comandos trap são normalmente colocados no início de um SS, mas eles podem estar em qualquer parte do script. As traps são assinalidas pelo Shell quando este Lê o comando trap. As traps são acionadas quando um sinal relacionado é recebido. Sintaxe: trap 'comandos' sinal1 sinal2 ... sinal n Exemplo: trap 'echo bye; exit ' 2 3 15 while tru; do echo “Hello ...” done Ignorando sinais O comando trap pode ser usado para ignorar determinados sinais quando estes forem recebidos pelo processo. Sintaxe: trap '' sinal1 sinal2 ... sinal n Exemplo: Ignora o sinal INT que é equivalente ao ^C. trap '' 2 whilte true; do echo “Hello ...” sleep 2 done Exemplo: gerenciar remoção de arquivos temporários se o programa for abortado trap 'rm /tmp/templfile; exit' 2 3 15
Exemplo: comando para ignorar sinais antes de sessos críticas de código trap '' 3 5 Exemplo: restaurar o trap para ação default quando uma seção de código sensível for completada trap INT QUIT TERM ou trap 2 3 15 As interrupções e sinais de término invocados por um comando são ignorados se este comando foi executado seguido do caracter &. Outros sinais tem valores herdados pelo shell de shellspai, com exceção do sinal 11. (seja comando trap).
Comandos especiais break [ n ] continue [ n ] cd [ arg ] echo [ arg ... ] eval [ arg ... ] exit [ n ] export [ name ... ] hash [ r ][ name ... ] newgrp [ arg ... ] pwd read [ name ... ] return [ n ] set [ aefhkntuvx [ arg ... ] ] shift [ n ] test times trap [ arg ] [ n ] type [ name ... ] ulimit [ f [ n ] ] umask [ nnn ] unset [ name ... ] wait [ n ] Chamada do sh Opções podem ser especificadas com um simples ou múltiplos argumentos, mas em todos os casos, cada opção deve iniciar com um . c string Se a chave c está presente, então os comandos estão lendo de uma string. s Se a chave s está presente, então os comandos estão lendo da entrada padrão, o shell irá de cada parametro posicional. i Se a entrada do shell estiver conectada a um terminal, então este shell é interativo, Neste caso: TERMINATE é ignorado(então o sinal 0 não mata shell interativo). r Shell restrito. sh pode retornar : 0 Sucesso
1 A execução do programa com erro (Veja Comandos especiais) 2 Sintax Error (Erro de Sintaxe) 3 Signal received that is not trapped
6.
6.
Exercicios
Exercicios
1. Qual é a shell mais utilizada pelo AIX/6000 ? 2. Quais são os dispositivos default de entrada e saida utilizados pelo sistema ? 3. É possível alterar os dispositivos de entrada e saida padrões ? Como ? 4. Que tipo de informação é enviada para a saida padrão ? 5. Que outro dispositivo pode ser usado no lugar da entrada padrão ? 6. Utilizando redirecionamento, como você faria para escrever um pequeno texto no arquivo carta ? 7. Qual a diferença entre os sinais > e >> ? 8. Qual a finalidade do dispositivo nulo ? 9. O redirecionamento utilizado em um comando é válido para os próximos ? Explique 10.É possível redirecionar mais do que um dispositivo padrão num só comando ? Caso afirmativo, faça um exemplo redirecionando todos os dispositivos padrões. 11. A ordem com que são feitos os redirecionamentos é relevante para a ação tomada pelo comando ? E usando associações ? Explique. 12.Explique os seguintes comandos : a) $ls 2> &1 > saida.do.ls b) $ls R / > erros 2> arvore c) $mailto claudia < carta d) $cat >> carta e) $ls l /usr > arvore 2> &1 f) $ls > saida.do.ls 2> &2 13.Utilizando a substituição de comandos, atribua a data de hoje no formato dd/mm/yy à variável TODAY. Consulte o manual online para verificar quais os formatos possíveis para a exibição de datas e/ou horas. 14.Liste o conteúdo do diretório de outro usuário usando a substituição do til ?15.Crie uma variável chamado MYNAME e armazene nela o seu primeiro nome. Como se mostra o conteúdo da variável ? 16.Como fazer para que o Shell filho “enxergue” o conteúdo da variável MYNAME ? 17.Torne a variável TODAY somenteleitura. É possível excluir esta variável ? 18.Modifique seu prompt de comando, de modo que ele fique com a aparência a seguir: [user1]10/10/2000 as 06:45/home/user1 => 19.Utilizando a substituição de comando copie o conteúdo de /home/teste para /tmp 20.Exiba o conteúdo do seu diretório home na saida padrão. 21.Copie a lista detalhada dos processos em execução para o arquivo lista.txt no seu diretório home. 22.Sabendo que a=1 b=2 c=3 Mostre na saida padrão começo32321meio34567fim utilizando os nomes das variáveis. 23. Escreva um SS que emita uma mensagen na sua tela a cada 3 segundos com um bip. Torne este SS imune aos sinais INT, HUP e TERM. Como parar este programa ?
Capitulo 2.
Capitulo 2.
Execução de Programas
Execução de Programas
Falaremos agora 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.
7.
7.
Execução em foreground e background
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 chamase 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 (Dependendo da máquina). 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: virtvs@mucuripe:~$ cp arquivo1 arquivo2 & [1] 206 virtvs@mucuripe:~$ 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]) chamase 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: virtvs@mucuripe:~$ cp arquivo1 arquivo2 & [1] 206 virtvs@mucuripe:~$ 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. 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é?): virtvs@mucuripe:~$ cp arquivo1 arquivo2 * aqui teclamos Ctrl + Z * [1]+ Stopped cp i arquivo1 arquivo2 virtvs@mucuripe:~$ bg 1 [1]+ cp i arquivo1 arquivo2 & virtvs@mucuripe:~$ 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 &.
8.
8.
Redirecionamento
Redirecionamento
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: virtvs@mucuripe:~$ 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: virtvs@mucuripe:~$ find / name "*.gz" > lista.txt find: /home/vera: Permissão negada find: /home/pri: Permissão negada find: /root: Permissão negada virtvs@mucuripe:~$ 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: virtvs@mucuripe:~$ 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: virtvs@mucuripe:~$ cat lista.txt /home/neo/gkrellm0.10.5.tar.gz /home/neo/linuxcallinterfacebeta.tar.gz ... <<< mais de 1000 linhas virtvs@mucuripe:~$ 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: virtvs@mucuripe:~$ 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 chamase "tee". Veja o exemplo a seguir: virtvs@mucuripe:~$ 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 "|".
echo
Existem alguns momentos que você não quer que a saída do echo pule de linha automaticamente. Para isso use o parâmetro "n". Este parâmetro é útil quando você vai entrar com algo após o echo. Veja este script: Exemplo: #!/bin/bash echo n "Entre com o nome do arquivo: " read FILE echo "Tipo do arquivo `file $FILE`" Muita atenção deve ser tomada ao usar o echo, pois as aspas que você pode vir a deixar de usar podem fazer um diferença (em alguns casos isso pode ser muito útil). Exemplo: $ echo uma boa rede de irc que conheco eh irc.linux.org uma boa rede de irc que conheco eh irc.linux.org $ echo "uma boa rede de irc que conheco eh irc.linux.org" uma boa rede de irc que conheco eh irc.linux.org $ $ # agora um exemplo com variavel $
$ TESTE="primeira linha da variavel > segunda linha > terceira... > chega! :) > " $ echo $TESTE primeira linha da variavel segunda linha terceira... chega! :) $ echo "$TESTE" primeira linha da variavel segunda linha terceira... chega! :) A esta altura você já deve ter se perguntado "Como faço para imprimir caracteres nova linha ou beep?!". Os mais malandrinhos devem ter tentado um contrabarra (backslash) '\', mas você não pode simplesmente fazer isso. É necessário usar o parâmetro "e" com o echo. Este parâmetro permite que usemos sequências de escape contrabarra. As sequências são iguais a da linguagem C, exemplo: \n para nova linha, \a para beep, \b para backspace, etc... Exemplo: $ echo e "module caiu de cara tentando \"top soul\".\nQue paia\a"! module caiu de cara tentando "top soul". Que paia! O e é também usado para escrever colorido e outras coisas interessantes. Veremos isso no tópico seguinte.
9.
9.
Metacaracteres
Metacaracteres
e Wildcards
e Wildcards
Metacaracteres são caracteres que possuem algum significado especial para o shell. Wildcards são subconjuntos dos metacaracteres cuja característica é simplificar a linha de comando. Os metacaracteres e wildcards serão vistos neste trabalho de uma maneira gradativa, a medida em que sejam necessários.Alguns deles já foram vistos no redirecionamento (> < e >> ). Veja mais alguuns metacaracteres: Caracteres Definição \ Continuação de linha ; Agrupamento de comandos
Caracteres Definição | Processamento Sequenciado O caracter \ (continuação de linha) permite continuar a escrever o comando na linha subsequente, caso o mesmo seja extenso, ou seja, não caiba em uma só linha da tela. Ressaltamos que não deverá haver espaço em branco após este caractere. Após pressionarmos a tecla [ENTER] o shell mostrará um novo prompt default (>) chamado de secundário, informando que a linha corrente é a continuação da linha anterior. Exemplo: $cat /home/chico/public_html/index.html \ > /home/maria/public_html/index.html O caracter de agrupamento de comando (;) permite agrupar os comandos em uma mesma linha. Sintaxe: $comando1 ; comando2 Exemplo: $ls ; pwd Isto é equivalente a digitar $ls $pwd É importante observar que o segundo commando não depende da resposta do primeiro comando, ou seja, não há relacionamento entre eles. Pipes Pipes ou tubos ( | ) é uma outra forma de agrupar comandos em uma mesma linha, porém, há relacionamento entre os comandos.
Quand utilizamos o “|” (pipe), ele informa ao shell para conectar a saida padrão do primeiro comando com a entrada padrão do segundo comando. Por sua vez, a saida do segundo comando é direcionada para a saida padrão. Para um melhor entendimento imagine que a linha de comando é um tubo por onde deve passar a informação do primeiro comando para o segundo, do segundo para o terceiro e assim sucessivamente, até que o último comando direcione a saida para a saida padrão. Agora vejamos o pipe. Sua sintaxe é: $ programa1 | programa2
O pipe é usado para você fazer da saída de um programa a entrada de outro (como usado no exemplo amarelinho.sh já mostrado anteriormente). Apesar de simples o pipe é muito útil e poderoso. Veja este exemplo muito simples: $ who meleu tty1 Nov 20 01:40 hack tty2 Nov 20 01:45 root tty3 Nov 20 02:44 $ who | cut c9 meleu hack root Comandos Úteis com o Pipe xargs O xargs transforma stdin em argumentos da linha de comando. Vamos usar o exemplo anterior de novo: Exemplo: $ who | cut c9 # lembrando: pipe transforma stdout em stdin meleu hack root $ # "echo" nao le arquivo, ele usa argumentos. $ # A linha abaixo nao tem utilidade. $ who | cut c09 | echo $ # "xargs" transforma o conteudo de stdin em argumentos $ who | cut c09 | xargs echo meleu hack root Como eu gosto do find não resisti e colocarei um comando interessante que usa pipe e xargs: $ find / perm 2 ! type l ! type c | xargs ls ld > wordwritable.txt tee Outro comando bom de se usar com pipe é o "tee". Ele faz com que a saída do programa vá para a saída padrão, normalmente a tela e para um arquivo ao mesmo tempo. É como se você fizesse "programa > arquivo" só que o saída do programa também seria escrita na saída padrão. Experimente:
$ ls la |tee conteudo.txt O comando echo e os cracteres de saida \b Backspace \c Suprime a terminação newline \f Alimentação de formulário \n Nova linha ( NewLine ) \r Carriage Return \t Tabulação \a Caractere de alerta \\ Barra invertida \0nnn Caractere de código ASCII em octal
10.
10.
Sequências de Escape ANSI
Sequências de Escape ANSI
Para usar cores a sequência de escape é "\e[<NUM>m" (os sinais '<' e '>' não entram!). Veja um exemplo (mais a frente você verá tabelas com os significados destas sequências): Examplo: #!/bin/bash # imprime amarelinho no centro da linha # A variável $COLUMNS contém o número de colunas que o terminal está # usando, e antes de executar este script você precisa exportála: # [prompt]$ export COLUMNS [ $COLUMNS ] || { echo Você precisa exportar a variável \"COLUMNS\": echo "Tente \"export COLUMNS\" e tente executar novamente" exit 1 } POSICAO=$[ ( $COLUMNS `expr length "$*"` ) / 2 ] # `expr length "$*"` retorna o número de caracteres digitados # como parâmetros. echo e "\e[${POSICAO}C\e[33;1m$*\e[0m" Agora uma explicação ligeira: o \e diz ao echo que o que vem depois é uma sequência de escape. Se você der a sequência '[<num>C', onde num é um número qualquer, o cursor vai andar "num" caraceteres para a direita. Acima eu uso a variável POSICAO para mover o cursor para o centro da linha (veja o cálculo no código). O comando '[<num>m' muda para a cor "num". Cada cor tem um código próprio. No exemplo acima o 33 faz ficar marrom, porém combinando com o 1 fica amarelo (isso no modo texto, pois no xterm, por exemplo, o 1 faz o marrom ficar em negrito. veja OBSERVAÇÕES mais adiante). Veja também uma tabela com os códigos de movimentação de cursor que eu conheço (os caracteres '<' e '>' devem ser ignorados):Código O que faz \e[<N>A Move o cursor N linhas acima. \e[<N>B Move o cursor N linhas abaixo. \e[<N>C Move o cursor N colunas à direita. \e[<N>D Move o cursor N colunas à esquerda. \e[<N>E Move o cursor N linhas para baixo na coluna 1. \e[<N>F Move o cursor N linhas para cima na coluna 1. \e[<N>G Coloca o cursor na linha N. \e[<L>;<C>H Coloca o cursor na linha L e na coluna C. \e[<N>I Move o cursor N tabulações à direita. \e[<N>J N=0 Apaga do cursor até o fim da tela; N=1 Apaga do cursor até o início da tela; N=2 Apaga a tela toda. \e[<N>K N=0 Apaga do cursor até fim da linha; N=1 Apaga do cursor até o início da linha; N=2 Apaga a linha toda. \e[<N>L Adiciona N linhas em branco abaixo da atual. \e[<N>M Apaga N linhas abaixo da atual. \e[<N>P Apaga N caracteres a direita. \e[<N>S Move a tela N linhas para cima. \e[<N>T Move a tela N linhas para baixo. \e[<N>X Limpa N caracteres à direita (com espaços). \e[<N>@ Adiciona N espaços em branco. \e[s Salva a posição do cursor. \e[u Restaura a posição do cursor que foi salva.
Agora uma tabelinha dos atributos e seus números (N deve estar no formato "\e[<N>m"): Atributo N Cor X Desligar todos atributos 0 Preto 0 Negrito 1 Vermelho 1 Cor X para o primeiro plano 3X Verde 2 Cor X para o segundo plano 4X Marrom 3 Sublinhado 4 Azul 4 Piscando (blink) 5 Roxo 5 Video reverso 7 Ciano 6 x Branco 7 OBSERVAÇÕES:
– Negrito, Sublinhado e Piscando possuem comportamentos diferentes no console e nos
emuladores de terminal. Principalmente quando temos negrito sendo usado com cores.
– Por exemplo, o código "\e[33m" irá ativar o marrom mas se for usado (no console!) com o
atributo de negrito ficará amarelo, e o código será assim: "\e[1;33m". Por isso faça os testes que você descobrirá as cores
– Estas tabelas eu fiz graças a uma matéria que o aurélio escreveu sobre isso. Veja em
http://verde666.org/coluna/ 2. read Como você viu no script anterior para entrar com um dado usase "read". O read tem alguns "macetinhos". Pra começar: você não precisa colocar um echo toda hora que for usar o read para escrever um prompt. Basta fazer "read p prompt variavel" Veja esta seção de exemplos: Examplo: #!/bin/bash read p "Entre com uma string: " string echo $string $ ./read1.sh