logo titulo
anterior indice proximo

O shell


O shell no Linux é o nome genérico de uma classe de programas que servem ao mesmo propósito: fornecer uma interface interativa, mas não visual, ao usuário ou operador, aonde comandos podem ser digitados, tarefas podem ser controladas e manipuladas, mantendo um ambiente (environment) aonde a configuração da aparência e parêmetros de alguns programas podem ser modificadas interativamente. Por outro lado, os shells também funcionam como linguagem de programação (interpretadas) e são uma forma relativamente eficiente mas menos custosa de se executarem tarefas complexas, sem a necessidade das fases clássicas de edição-compilacão-depuração. Concentraremos nossos esforços no bash, que é indubitavelmente o shell mais popular no Linux, mas grande parte desses conceitos se aplicam a outros shells igualmente.

Cada shell tem um environment (ambiente, em portugues) que é um simples banco de dados em forma de texto, relacionando nomes de variáveis com os seus valores. Algumas variáveis são muito importantes, pois controlam aonde o bash irá procurar programas para executar, qual o tipo de terminal que estamos usando, e outras propriedades realacionadas com o nosso ambiente particular. No login, o bash executa inicialmente /etc/profile, e depois algum dos arquivos[18] ~/.profile , ~/.bash_profile ou ~/.bash_login, definindo assim o ambiente inicial do usuário. Se o shell é interativo, isto é, ele está conectado a um terminal (em oposição a um shell em batch-mode), ele lerá também o arquivo ~/.bashrc.

environment

o environment

As variáveis ao lado são as mais comuns, mas não de maneira exuastiva. Muitos programas se comunicam com outros através deste mecanismo bastante simples. PATH indica o local aonde o bash deverá procurar por programas executáveis. SHELL deverá conter /bin/bash (ou outro shell, se voce o estiver utilizando), DISPLAY é relacionado ao X11 (X-Windows), Se voce estiver em X, um programa-cliente verá :0.0 nesta variável. WINDOWID contém o id da janela do programa em X. (contudo observe que o número retornado é em decimal e não hexadecimal como o seu window manager pode mostrar)
TERM conterá o tipo de terminal, geralmente xterm ou linux (se voce estiver na console), mas muitos outros terminais (centenas) são suportados.
MANPATH é uma lista semelhante ao PATH, mas com os lugares que o man procurará para mostrar manpages. PS1 e PS2 são os prompts (nível 1 e 2) que serão mostrados pelo bash para lhe requisitar uma linha de comando. Poderão ser colocados aí sequências especiais para mostrar data/hora, nome do usuário, host (servidor), espaço em disco disponível, bem como caracteres que mudam a coloração destas informações.
HOME é uma das mais importantes: mostra o seu diretório home (/home/<usuário>) e é o substituto do "~" que introduzimos com os nomes completos de arquivos. LOGNAME contém o nome do usuário, preenchido durante o seu login. A propósito, o programa login é quem estabelece os valores das variáveis HOME, PATH, SHELL, TERM, MAIL, e LOGNAME.
USER conterá o nome do usuário (aproximadamente o mesmo que LOGNAME), mas não é usada de forma padrão no Linux.
LINES e COLUMNS contém (como o próprio nome indica) o tamanho da tela.

Outras variáveis do environment são PPID, UID, EUID, correspondendo aos valores de id de usuário e "programa-pai" que já discutimos. Algumas variáveis têm significado especial, e são modificadas diretamente pelo bash: RANDOM mostra um número aleatório (inteiro) cada vez que é referenciada; SECONDS mostra o número de segundos desde o início do presente processo (bash) foi criado; LINENO mostra um número sequencial da linha corrente, mas não linha do terminal e sim a n-ésima linha de comando solicitada ao bash.

usando o bash interativamente


Para visualizar quaisquer das variáveis do environment, usamos a substituição de parâmetros do bash e o comando echo para nos mostrar esse valor substituido, por exemplo:

    echo $RANDOM

nos mostrará números aleatórios a cada vez que é executado. Para modificar um destes valores, simplesmente uma atribuição com o sinal de = é suficiente, exceto que o seu valor só permanece durante o comando presente. Usualmente queremos que "de agora em diante" o valor seja modificado, seja persistente. Para isso o comando export é necessário:

    export CURSO=sysadmin

ou em outra forma mais explícita (separando os dois comandos):

    
    CURSO=sysadmin
    export CURSO

O bash tem comandos builtins (já incorporados ao programa bash) que são de outra forma indistinguíveis dos comandos que discutimos em capítulos anteriores. Um comando builtin, entretanto, não abre nenhum arquivo executável, e assim é bem mais rápido a sua execução. Outra diferença sutil, é que não haverá manpage para um builtin. No seu lugar, usaremos o (builtin também, evidentemente) help seguido do nome do comando que desejamos obter informação. No caso de comandos externos, o (programa) man faz esse papel.

Podemos executar comandos externo e retornar imediatamente, mesmo sem esperar que o comand termine, colocando um "&" no final da linha de comando:

comando &

Podemos também executar vários comandos em sequência, separando-os com um ponto-e-vírgula:

comando1 ; comando2

Outras formas de controlar logicamente a execução de comandos é através de operadores lógicos && e ||:

comando1 && comando2

comando1 || comando2

A primeira destas formas executa comando2 somente se o comando1 for bem sucedido (não der erro). A segunda executa o comando2 somente se o comando1 falhar. (&& corresponde a um AND, || corresponde a um OR lógico)

cd

troca o diretório corrente. Usado sem parâmetros vai para o diretório $HOME (contido na variável HOME) Colocando os diretórios mais usados na variável CDPATH (separados por ":") podemos trocar para qualquer subdiretório dos contidos nessa lista sem introduzir os seus paths completos.

pwd

mostra o diretório corrente, de forma absoluta, isto é, sem o "~" que indica o nosso home dir.

echo

ecoa os argumentos no terminal, após fazer as expansões (substituições) de variáveis, comandos, etc.

umask

define (ou mostra, sem argumentos) a máscara que será usada na criação de novos arquivos. Essa máscara contém as permissões (rwx) que vimos anteriormente. Usando umask -S a mesma coisa se processa simbolicamente, ao inves de ser em octal (default).

exit, bye

esses comandos terminam o shell, opcionalmente retornando um número que seja dado como parãmetro. (no caso exit 3, por exemplo o status retornado será 3)

help

um dos mais úteis comandos (principalmente para que é principiante!) para fornecer informações sobre os comandos builtins do bash.

expansão e substituição


O bash efetua uma série de substituições nos argumentos que lhes são fornecidos. As mais comuns são até familiares para quem já é usuário do MsDos, que é a substituição de wildcards em nomes de arquivos. Mas o bash vai bem além, permitindo o uso de classes de caracteres e múltiplos "*" nos nomes de arquivos. Outras substituições não tão familiares também existem, com alguns exemplos introdutórios [19]:

substituição de chaves

É expandida como a combinação de todos os elementos entre as chaves, separados por vírgulas. O segundo exemplo mostra um simples "gerador de pronomes" brasileiros. Observe que em {,s} o primeiro parâmetro é nulo, mas a vírgula, evidentemente, é necessária.

~$ echo ago{r,ni}a
agora agonia

~$ echo {a,o}{,s}
a as o os

substituição de comandos

O resultado da execução do comando é colocado no lugar do argumento. Esta subsituição vem em dois formatos: $(comando) ou `comando`. Aqui o comando which devolve o path completo do argumento (outro programa). Compare com o segundo resultado!

~$ echo o path para ls é `which ls`
o path para ls é /bin/ls

~$ echo o path para ls é which ls
o path para ls é which ls

expansão de wildcards

É a já familiar expansão dos "*" (asteriscos) por qualquer número de caracteres; "?" por um único caracter; adicionalmente "[abc]" é substituido por "um destes" e "[^abc]" por "um exceto estes" caracteres.
O formato "[a-h]" serve também para indicar caracteres "entre estes". Ademais são válidas combinações dos conceitos acima. Veja também como o echo pode ser usado (o normal seria ls) para listar arquivos, dado a expansão efetuada pelo bash. Outros padrões mais complexos serão tratados no capítulo sobre programação com o shell.

~$ echo *.htm*
cap01.html politica.htm

~$ ls cap0[3-5]*
cap03.html cap04.html cap05.html

~$ ls cap0[^1-7]*
cap08.html cap09.html

substituição do til "~"

O til é expandido somente quando está no início de uma palavra, sendo substituido pelo conteúdo da variável HOME (o diretório home do usuário). Além disso, os prefixos "~+" e "~-" são supstituidos, respectivamente, pelas variáveis PWD e OLDPWD (diretório corrente e anterior ao último cd executado).

~$ echo ~ , ~-
/home/rildo , /home/rildo/projetos
expansão de variáveis e parâmetros

É o desdobramento do nome de variável, prefixado por "$" no seu valor, contido no environment, mas outras formas de usar este mecanismo existem. Mostraremos só algumas mais comuns.
${VAR} é equivalente a $VAR. ${#VAR} retorna o tamanho (em caracteres) dessa variável. ${VAR:-subst} retorna o valor ou o valor dado como substituto (subst) caso a variável seja nula ou não exista.

~$ export CURSO="Administração de Sistemas"

~$ echo $CURSO
Administração de Sistemas

~$ echo ${#CURSO}
25

~$ echo ${MEUCURSO:-inexistente}
inexistente

expansão aritmética

O bash permite fazer alguns cálculos simples (para cálculos com precisão infinita, use bc, uma calculadora programável)

~$ echo $((3*5))
15

~$ echo $((2+${#CURSO}))
27


Outras substituições serão vistas posteriormente, mas aconselhamos brincar um bocado com estas, pois existem nuances que só a utilização (e a consulta da manpage: man bash) revelam.

Algumas vezes queremos evitar a substituição de variáveis ou remover o significado especial de caracteres. Isso é chamado dequoting, e pode ser feito de várias maneiras.
  1. encapsulando a frase entre apóstrofes: 'frase a serquoted'
  2. encapsulando entre aspas:"frase (quase) sem interpretação"
  3. prefixando cada caracter especial com uma barra invertida (backslash):echo \*

No segundo caso, as substituições de variáveis (prefixo $), comandos (entre acentos graves `) e caracteres prefixados com a barra invertida, continuarão sendo efetuadas. Observe que o último caso ecoará apenas um asterisco, e não todos os arquivos, o que seria resultada da expansão de wildcards como vimos acima.

O bash usa a biblioteca readline (mais outra excelente herança GNU), que lhe dá uma potência considerável na edição de linhas, tratamento da historia (history, comandos previamente executados), e para complementação de palavras parcialmente digitadas. Para o principiante, entretanto, é uma miríade de comandos novos, nem sempre muito amigáveis para memorizar. Todavia, o bash tem um builtin muito especial para nos socorrer nesse caso, o comando fc. Com ele re-editamos uma linha introduzida anteriormente usando o editor da nossa preferência (joe, tão bom que não precisei mostrar os comandos dele. São triviais para quem já usou algum WordStar-like anteriormente). Para abrir a edição de uma linha previamente introduzida, entre fc <parte da linha> e ele vai buscá-la. Quando saimos do editor, a linha editada é executada. Simples, não?

Mesmo assim, há vezes em que voce precisará realmente editar a linha de comando, portanto eis aqui um resumo dos principais controles de edição:

Ctrl-B move para trás um caracter sem apagá-lo
Ctrl-F move à frente um caracter
Del apaga um caracter (digitado antes)
Ctrl-D apaga o caracter à frente do cursor
Ctrl-A move para o início da linha
Ctrl-E move para o final da linha
Ctrl-P move para a linha anterior (já executada)
Ctrl-N move para a próxima linha
Esc ? tenta completar o nome do comando (dado parcialmente)
Ctrl-C aborta o comando que está sendo executado
Ctrl-Z suspende, mas não aborta, o comando sendo executado
Ctrl-S suspende a saida para o terminal do programa executando
Ctrl-Q restaura a sida para o terminal (vide comando anterior)

Os quatro últimos controles na verdade se relacionam mais com controle de tarefas que edição de linhas, mas preferimos mostrá-los aqui. Muitos desses comandos podem ser executados também pelas teclas com setas do terminal, mas é bom conhecê-los pois muitas vezes o terminal está mal configurado. Além desses, outros controles indispensáveis são so que permitem revisar o texto (saida) quando passa do tamanho da tela (Ctrl-PgUp e Ctrl-PgDown), e os que mudam de terminal virtual (Alt-F1 a Alt-F10, dependendo do número de terminais configurados). Se voce estiver em X-Windows, o certo é Ctrl-Alt-F1 no lugar de Alt-F1.

O bash possui alguns builtins para controle de processos: jobs lista os jobs atualmente executando, kill %n termina o job de número n, bg põe um job em background, fg põe um job em foreground. Os jobs são processos controlados pelo shell corrente, mas com uma numeração localizada, diferente da obtida com o comando ps.

redirecionamento de entrada e saida


No Linux existem três arquivos pré-definidos para um programa, inclusid\ve para o próprio shell: stdin, stdout e stderr, abreviaturas de standard input, output, e error. Este comportamento se confunde com o da linguagem C, que foi criada exatamente para re-escrever o Unix (no final da década de 70) numa forma mais portável para várias arquiteturas (CPUs) diferentes.

Quando um programa "conversa" com o seu terminal, ele recebe caracteres do stdin, que corresponde aos dados introduzidos no teclados dele, e envia caracteres para o stdout, que corresponde à tela deste terminal. Se todos os programas só funcionassem assim, teríamos que estar constantemente digitando informações para obter respostas, que não seriam armazenadas em lugar algum!
Evidentemente, precisamos de uma forma melhor de reutilizar programas prontos, como pro exemplo o programa sort, que lê o que é introduzido na sua entrada (stdin) e escreve em ordem alfabética na sua saida (stdout). Quando um programa encontra um erro de sintaxe, usualmente ele escreve no stderr (saida de erro) o que está errado. O bash nos fornece vários comandos para controlar efetivamente para onde vai essa entrada e saida, permitindo também concatenar vários programas, literalmente "conectados" entre si, de acordo com uma metáfora que lembra encanamentos (pipes) de uma distribuição de água, por exemplo.

redireção de I/O

Os comandos podem ter suas entradas/saidas redirecionadas para arquivos. Na figura, cmd é o nome de algum comando (qualquer) que estamos considerando; saida, entrada, erro, são arquivos. O primeiro caso redirige a saida (o que seria impresso no terminal) para o arquivo saida. No segundo, a entrada (o que seria teclado) vem do arquivo entrada. Quando um programa (por exemplo um compilador) gera muitas mensagens de erro, o terceiro caso pode ser mais útil para nós, mostrando tanto a saida normal quanto a saida de erro, no arquivo saida+erro. O quarto caso redirige o descritor de arquivo número 5 (caso o programa abra pelo menos mais dois arquivos!) para o arquivo saida_descr_5 (ou outro nome mais bonito que escolhermos). Ãs vezes queremos põr a saida num arquivo que já contém informações preciosas, que não queremos perder. Nesse caso, a quinta linha adiciona a saida do comando no final do arquivo saida_adic dado. Finalmente, podemos desejar que a saida de um comando seja usada como entrada de outro comando. A última linha faz exatamente isso. Nesse caso, a entrada do cmd1 virá do stdin, e a saida do cmd2 irá para stout, como esperado.

redireção


rpragana
Wed Jan 6 19:22:56 EDT 1999