shell

Definição

Os comandos digitados pelo usuário são interpretados pelo shell. Esses comandos podem ser comandos embutidos do shell, mas na maioria das vezes eles são programas externos.

O shell analisa sintaticamente a linha de comando depois que ela é lida. A variável de ambiente IFS determina como isso é feito. Normalmente, IFS é configurada de tal forma que espaços em branco separam os diferentes argumentos de linha de comando.

Existem vários shells para Linux, onde cada shell tem seus próprios recursos, capacidades e limitações. Por exemplo, o shell padrão para a distribuição Conectiva é o bash.

Na realidade, o shell é apenas um arquivo executável armazenado em /bin. No modo gráfico, um shell é executado em cada terminal aberto.

Para ver qual é o seu shell padrão, basta digitar o comando

printenv SHELL

O comando acima exibe o conteúdo da variável ambiente SHELL que contém o caminho completo do shell. Outra forma de saber qual é o shell padrão, é verificar o último parâmetro definido para o usuário no arquivo /etc/passwd. Por exemplo,

aluno:x:501:501::/home/aluno:/bin/bash

mostra que o usuário aluno usa o shell bash.

Carregando o shell

Suponha que o shell padrão do sistema seja o bash. Então, quando o usuário acessa o sistema, o bash carrega os seguintes arquivos do diretório home do usuário (estes arquivos são criados automaticamente pelo comando adduser, veja o diretório /etc/skel para saber quais são os arquivos padrão no seu sistema):

  1. .bashrc : contém funções e nomes alternativos definidos pelo usuário.
  2. .bash_history : contém a lista dos últimos (o padrão é 1000) comandos digitados pelo usuário.
  3. .bash_logout  : contém os comandos executados pelo sistema no fechamento da sessão pelo usuário.
  4. .bash_profile : contém as variáveis de ambiente do usuário.

e os seguintes arquivos do diretório /etc:

  1. bashrc : contém funções e nomes alternativos (aliases) do sistema.
  2. profile : contém as variáveis de ambiente do sistema.

Os arquivos no diretório home são exclusivos do usuário e portanto, uma alteração nestes arquivos afeta apenas o usuário em questão. Os arquivos do /etc são comuns a todos os usuários e portanto, uma alteração nestes arquivos afeta todos os usuários do sistema.

Os arquivos carregados pelo shell definem as variáveis de ambiente, que nada mais são que definições e valores que o shell e os outros programas do sistema reconhecem. Para ver quais as variáveis de ambiente no seu sistema você pode digitar printenv, env ou set. Por exemplo, são algumas das variáveis de ambiente do bash:

É possível criar novas variáveis, excluir variáveis existentes ou apenas alterar o conteúdo de uma variável de ambiente.

Para criar uma nova variável de ambiente, basta definir o nome e o valor da nova variável de ambiente e usar o comando export para permitir que a variável seja visualizada pelos aplicativos (por exemplo, um novo shell ou um novo terminal) inicializados no mesmo terminal (neste caso a variável existirá enquanto a sessão estiver aberta). Por exemplo,

TESTE=10; export TESTE

ou

export TESTE=10

cria a variável de ambiente TESTE com valor inicial 10. O comando export faz com que a nova variável seja conhecida por todos os processos a partir deste shell. Os nomes das variáveis de ambiente são, tradicionamente, definidas usando apenas letras maiúsculas. Entretanto, isto não é obrigatório. Você pode também usar letras minúsculas. Mas, CUIDADO! O Linux é case sensitive. Isto significa que o sistema diferencia letras maiúsculas de letras minúsculas. Portanto, o comando

teste=10; export teste

cria uma nova variável de ambiente chamada teste e que é diferente da variável TESTE criada anteriormente.

É importante observar que as variáveis de ambiente definidas a partir da linha de comando são temporárias. Para criar uma variável permanente, deve-se acrescentar a definição e o comando export no arquivo .bash_profile (no caso de shell bash).

Para excluir uma variável de ambiente, deve-se usar o comando unset. Por exemplo, o comando

unset teste

exclui a variável de ambiente teste criada no exemplo anterior.

Para alterar o valor de uma variável de ambiente, basta fornecer o nome da variável e o novo valor a ser atribuido a variável. Para a variável de ambiente TESTE definida anteriormente nesta seção, podemos digitar

TESTE=200

e a variável TESTE passa a ter valor 200. Neste caso, o conteúdo da variável é completamente alterado. Pode ser que ao invés de alterar o conteúdo, você queira apenas acrescentar mais alguma informação ao conteúdo armazenado em uma variável. Por exemplo, suponha que você queira acrescentar o diretório /teste/bin no caminho de busca, ou seja, no PATH. Devemos, então digitar

PATH=$PATH:/teste/bin

O símbolo $ usado acima antes de PATH informa ao shell para usar o conteúdo da variável de ambiente PATH.

Suponha agora que temos USER=aluno e que queremos USER=aluno linux. Então podemos definir

USER="$USER Linux"

As aspas acima são necessárias devido ao espaço em branco existente no novo conteúdo da variável USER. Note que novamente usamos $ para indicar ao shell que se deve substituir o nome USER pelo conteúdo da variável ambiente USER.

Os exemplos mostrados acima são alterações temporárias no ambiente do usuário. Para tornar uma alteração efetiva, deve-se alterar o arquivo profile do usuário (.bash_profile no shell bash). Por exemplo, suponha que queremos personalizar o prompt das linhas de comando. Podemos então incluir no arquivo de profile

PS1="[\W]\$"

e

export PS1

onde o novo prompt apenas exibe o nome do diretório atual de trabalho do usuário (\W) e o símbolo $ ( \$ ).

Consulte o manual on line para conhecer um pouco mais sobre os comandos embutidos no seu shell (por exemplo, man bash para ler sobre o script bash).

Usando as variáveis de ambiente em um programa C

O terceiro argumento da função main() é a lista de variáveis de ambiente. Em um programa C, pode-se usar a função putenv() para criar/alterar variáveis de ambiente, a função getenv() para obter o valor das variáveis e a função unsetenv() para remover variáveis.

O exemplo mostrado a seguir exibe um dump das variáveis de ambiente e de algumas funções de C, antes e depois, que algumas modificações são introduzidas no ambiente do sistema.

1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<unistd.h>
4 #include<string.h>
5 #include<errno.h>
6 void imprime_variavel(const char *desc, const void *addr)
7 {
8 printf("0x%08lX %-s\n", (long)addr, desc);
9 }
10 void dump(char * const envp[], const char *cabecalho)
11 {
12 int x; /* índice envp[x] */
13 /* Exibe um título */
14 printf("\n%s\n\n", cabecalho);
15
16 /* Exibe as variáveis de ambiente */
17 for (x = 0; envp[x] != 0; ++x)
18 {
19 imprime_variavel(envp[x], envp+x); /* imprime variável */
20 }
21 /* Exibe outras variáveis */
22 imprime_variavel("stderr",stderr);/* Dump do endereço de stderr */
23 imprime_variavel("stdout",stdout);/* Dump do endereço de stdout */
24 imprime_variavel("stdin", stdin); /* Dump do endereço de stdin */
25 imprime_variavel("dump", dump); /* Dump do endereço de main */
26 }
27 int main(int argc, char * const argv[], char * const envp[])
28 {
29 /* Faz dump das variáveis de ambiente */
30 dump(envp, "AMBIENTE INICIAL:");
31 /* inclui duas novas variáveis de ambiente */
32 if (putenv("TESTE1=100") == -1)
33 {
34 printf("%s: putenv()\n", strerror(errno));
35 exit(1);
36 }
37 if (putenv("TESTE2=teste de variaveis") == -1)
38 {
39 printf("%s: putenv()\n", strerror(errno));
40 exit(2);
41 }
42 /* altera valor da variável de ambiente LOGNAME */
43 if (putenv("LOGNAME=linux") == -1)
44 {
45 printf("%s: putenv()\n", strerror(errno));
46 exit(3);
47 }
48 /* Faz dump das variáveis de ambiente */
49 dump(envp, "AMBIENTE Modificado:");
50 /* Verifica o valor de LOGNAME, TESTE1 e TESTE2 */
51 printf("\ngetenv(LOGNAME) = %s;", getenv("LOGNAME"));
52 printf("\ngetenv(TESTE1) = %s;", getenv("TESTE1"));
53 printf("\ngetenv(TESTE2) = %s;\n", getenv("TESTE2"));
54 return 0;
55 }

Uma observação interessante em relação ao programa acima diz respeito ao envp[] antes e depois da alteração da variável LOGNAME e da inclusão das variáveis TESTE1 e TESTE2 : o array envp[] não se altera. Isto significa que as alterações introduzidas pelo programa no ambiente são feitas em outra área de memória e monitoradas pelo sistema enquanto o programa está sendo executado. Não é possível alterar as variáveis de ambiente do shell pois as variáveis do shell são definidas na própria memória privada do shell.

Alteração do shell

É possível mudar de shell em tempo de execução. Para isto, basta digitar o nome do novo shell na linha de comandos. Para encerrar o novo shell e voltar para o shell anterior basta digitar exit. Para ver quais os shells que estão disponíveis no sistema, basta digitar

chsh -l

Na realidade, este comando exibe o conteúdo do arquivo /etc/shells. Para mudar o shell padrão, o usuário pode usar o comando chsh (change shell). Suponha, por exemplo, que queremos adotar como padrão o shell ash, então podemos digitar

chsh -s /bin/ash

O Linux apenas pedirá a senha do usuário logado para confirmar a alteração. Na próxima vez que o usuário logar no sistema, o ash será o seu shell padrão. O uso do comando chsh, sem parâmetros, fará com que, além da senha, o Linux também solicite o nome do novo shell. Neste caso, deve-se fornecer o caminho completo do novo shell.

É também importante observar que quando uma nova sessão é aberta com o comando bash, apenas os arquivos /etc/bash e ~/.bashrc são lidos. Nestes arquivos são colocados os comandos que devem continuar existindo na nova sessão como, por exemplo, os aliases.

Programação em shell script

Como vimos acima, o shell funciona como mediador entre o usuário e o kernel do sistema. Quando o usuário digita um comando, o shell analisa o comando e solicita ao kernel a execução das ações correspondentes ao comando em questão.

Normalmente, o usuário (principalmente se ele é o administrador do sistema) executa um mesmo conjunto de tarefas diariamente. O ideal então é que o usuário possa automatizar as suas tarefas, ou seja, o usuário digita um único comando e o shell o interpreta como um conjunto de comandos a serem executados pelo sistema. Este tipo de automatização de tarefas é possível através da programação shell. Abaixo mostramos alguns exemplos de scripts.

É importante observar que existe outra forma de executar os scripts. Ao invés de alterar as permissões de acesso do script com o comando chmod, pode-se simplesmente especificar o nome do shell na linha de comando. Por exemplo, suponha que queremos executar o arquivo teste usando o script bash. Então podemos digitar

bash teste