3.3 Lição 1
Certificação: |
Linux Essentials |
---|---|
Versão: |
1.6 |
Tópico: |
3 O poder da linha de comando |
Objetivo: |
3.3 Como transformar comandos em script |
Lição: |
1 de 2 |
Introdução
Até agora, aprendemos a executar comandos a partir do shell, mas também é possível inserir comandos em um arquivo e depois configurá-lo para ser executável. Quando executamos o arquivo, os comandos são rodados um após o outro. Esses arquivos executáveis são chamados scripts e representam uma ferramenta absolutamente essencial para qualquer administrador de sistema Linux. Basicamente, podemos dizer que o Bash, além de um shell, é uma verdadeira linguagem de programação.
Exibindo a saída
Vamos começar demonstrando um comando que você deve ter visto nas lições anteriores: o echo
imprime na tela um argumento na saída padrão.
$ echo "Hello World!" Hello World!
Agora, usaremos um redirecionamento de arquivo para enviar este comando para um novo arquivo chamado new_script
.
$ echo 'echo "Hello World!"' > new_script $ cat new_script echo "Hello World!"
O arquivo new_script
agora contém o mesmo comando de antes.
Tornando um script executável
Vamos demonstrar algumas das etapas necessárias para executar esse arquivo da maneira esperada. A primeira ideia de um usuário pode ser simplesmente digitar o nome do script, assim como digitaria o nome de qualquer outro comando:
$ new_script /bin/bash: new_script: command not found
Sabemos que new_script
existe em nossa localização atual, mas note que a mensagem de erro não está dizendo que o arquivo não existe, mas sim que o comando não existe. Seria útil discutir como o Linux lida com comandos e executáveis.
Comandos e PATH
Quando digitamos o comando ls
no shell, por exemplo, estamos na verdade executando um arquivo chamado ls
que existe em nosso sistema de arquivos. Para comprovar, use which
:
$ which ls /bin/ls
Seria cansativo digitar o caminho absoluto de ls
toda vez que desejássemos examinar o conteúdo de um diretório, por isso o Bash tem uma variável de ambiente que contém todos os diretórios em que ficam os comandos que queremos executar. Para ver o conteúdo dessa variável, use echo
.
$ echo $PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
O shell espera encontrar um comando em cada um desses locais, delimitado por dois pontos (:
). Note que /bin
está presente, mas é seguro supor que nossa localização atual não está. O shell procurará por new_script
em cada um desses diretórios, mas não o encontrará e, portanto, exibirá a mensagem de erro que vimos acima.
Existem três soluções para esse problema: podemos mover new_script
para um dos diretórios de PATH
, podemos adicionar o diretório atual a PATH
, ou podemos mudar a maneira de chamar o script. A última solução é a mais fácil, pois simplesmente requer que especifiquemos o local atual ao chamar o script usando ponto e barra (./
).
$ ./new_script /bin/bash: ./new_script: Permission denied
A mensagem de erro já está diferente, o que indica que fizemos alguns progressos.
Permissões de execução
A primeira investigação que um usuário deve fazer nesse caso é usar ls -l
para examinar o arquivo:
$ ls -l new_script -rw-rw-r-- 1 user user 20 Apr 30 12:12 new_script
Podemos ver que as permissões para este arquivo estão definidas como 664
por padrão. Ainda não configuramos este arquivo para ter permissões de execução.
$ chmod +x new_script $ ls -l new_script -rwxrwxr-x 1 user user 20 Apr 30 12:12 new_script
Este comando concede permissões de execução a todos os usuários. Esteja ciente de que isso pode ser um risco de segurança, mas, por enquanto, esse é um nível aceitável de permissão.
$ ./new_script Hello World!
Agora já é possível executar nosso script.
Definindo o intérprete
Como demonstramos, é possível simplesmente inserir texto em um arquivo, configurá-lo como executável e executá-lo. O new_script
ainda é tecnicamente um arquivo de texto normal, mas pode ser interpretado pelo Bash. Mas e se ele estiver escrito em Perl ou Python?
É extremamente recomendável especificar o tipo de intérprete que queremos usar na primeira linha de um script. Essa linha é chamada de bang line, ou, mais comumente, shebang. Ela indica ao sistema como queremos que aquele arquivo seja executado. Como estamos aprendendo Bash, usaremos o caminho absoluto para o nosso executável do Bash, mais uma vez usando which
:
$ which bash /bin/bash
Nosso shebang começa com um sinal de hash e um ponto de exclamação, seguidos pelo caminho absoluto acima. Vamos abrir new_script
em um editor de texto e inserir o shebang. Vamos também aproveitar a oportunidade para inserir um comentário em nosso script. Os comentários são ignorados pelo intérprete. Eles são escritos para o benefício de outros usuários que queiram entender seu script.
#!/bin/bash # Este é nosso primeiro comentário. Também é recomendável documentar todos os scripts. echo "Hello World!"
Também faremos uma alteração adicional no nome do arquivo: salvaremos o arquivo como new_script.sh
. O sufixo do arquivo ".sh" não altera em nada a execução do arquivo. É uma convenção que os scripts do bash sejam rotulados com .sh
ou .bash
para identificá-los mais facilmente, assim como os scripts em Python são geralmente identificados com o sufixo .py
.
Editores de texto comuns
Os usuários do Linux geralmente precisam trabalhar em ambientes nos quais editores de texto gráficos não estão disponíveis. Portanto, é altamente recomendável aprender ao menos o básico sobre a edição de arquivos de texto na linha de comando. Dois dos editores de texto mais comuns são vi
e nano
.
vi
O vi
é um editor de texto venerável, que vem instalado por padrão em quase todos os sistemas Linux existentes. O vi
gerou um clone chamado vi IMproved ou vim
, que tem algumas funcionalidades adicionais, mas mantém a interface do vi
. Embora trabalhar com o vi
seja assustador para um novo usuário, o editor é popular e amado pelos usuários que conhecem seus muitos recursos.
A diferença mais importante entre o vi
e aplicativos como o Bloco de Notas é que o vi
possui três modos diferentes. Na inicialização, as teclas H, J, K e L são usadas para navegar, e não para digitar. Nesse _ modo de navegação_, pressionamos I para entrar no modo de inserção. A partir daí, você pode digitar normalmente. Para sair do modo de inserção, pressione Esc para retornar ao modo de navegação. No modo de navegação, pressione : para entrar no modo de comando. Nesse modo, podemos salvar, excluir, sair ou alterar opções.
Embora o vi
tenha uma curva de aprendizado, os diferentes modos permitem que um usuário experiente seja mais eficiente do que com outros editores.
nano
O nano
é uma ferramenta mais recente, criada para ser mais simples e fácil de usar do que o vi
. O nano
não oferece modos diferentes. Em vez disso, um usuário pode começar a digitar já na inicialização, usando Ctrl para acessar as ferramentas impressas na parte inferior da tela.
[ Welcome to nano. For basic help, type Ctrl+G. ] ^G Get Help ^O Write Out ^W Where Is ^K Cut Text ^J Justify ^C Cur Pos M-U Undo ^X Exit ^R Read File ^\ Replace ^U Uncut Text ^T To Spell ^_ Go To Line M-E Redo
Os editores de texto são uma questão de preferência pessoal, e o editor que você escolher não fará diferença para esta lição. Mas vale muito a pena procurar conhecer e se familiarizar com um ou mais editores de texto.
Variáveis
As variáveis são uma parte importante de qualquer linguagem de programação, e o mesmo vale para o Bash. Quando iniciamos uma nova sessão no terminal, o shell já define algumas variáveis automaticamente. A variável PATH
é um bom exemplo. Nós as chamamos de variáveis de ambiente, porque geralmente definem características do nosso ambiente shell. É possível modificar e adicionar variáveis de ambiente, mas por enquanto vamos nos concentrar na configuração de variáveis dentro do nosso script.
Vamos modificar o script da seguinte forma:
#!/bin/bash # Este é nosso primeiro comentário. Também é recomendável documentar todos os scripts. username=Carol echo "Hello $username!"
Neste caso, criamos uma variável chamada username
e atribuímos a ela o valor Carol
. Note que não há espaços entre o nome da variável, o sinal de igual ou o valor atribuído.
Na linha seguinte, usamos o comando echo
com a variável, mas há um cifrão ($
) na frente do nome da variável. Isso é importante, pois indica para o shell que queremos tratar username
como uma variável, e não apenas como uma palavra normal. Ao digitar $username
no comando, indicamos que queremos executar uma substituição, trocando o nome de uma variável pelo valor atribuído a essa variável.
Ao executar o novo script, obtemos esta saída:
$ ./new_script.sh Hello Carol!
-
As variáveis devem conter apenas caracteres alfanuméricos ou sublinhados (underline) e diferenciam maiúsculas de minúsculas.
Username
eusername
serão tratados como variáveis distintas. -
A substituição de variáveis também pode ter o formato
${username}
, com a adição de{ }
. Isso também é aceitável. -
As variáveis no Bash têm um tipo implícito, sendo consideradas strings. Isso significa que executar funções matemáticas no Bash é mais complicado do que seria em outras linguagens de programação, como C/C++:
#!/bin/bash # Este é nosso primeiro comentário. Também é recomendável documentar todos os scripts. username=Carol x=2 y=4 z=$x+$y echo "Hello $username!" echo "$x + $y" echo "$z"
$ ./new_script.sh Hello Carol! 2 + 4 2+4
Usando aspas com variáveis
Vamos fazer a seguinte alteração no valor da nossa variável username
:
#!/bin/bash # Este é nosso primeiro comentário. Também é recomendável documentar todos os scripts. username=Carol Smith echo "Hello $username!"
A execução desse script resultará em um erro:
$ ./new_script.sh ./new_script.sh: line 5: Smith: command not found Hello !
Lembre-se de que o Bash é um intérprete e, como tal, interpreta o script linha por linha. Neste caso, ele interpretou corretamente username=Carol
como a definição de uma variável username
com o valor Carol
. Mas, em seguida, ele interpretou que o espaço indicava o final dessa tarefa e que Smith
era o nome de um comando. Para que o espaço e o nome Smith
sejam incluídos como o novo valor da variável, colocamos aspas duplas ("
) ao redor do nome.
#!/bin/bash # Este é nosso primeiro comentário. Também é recomendável documentar todos os scripts. username="Carol Smith" echo "Hello $username!"
$ ./new_script.sh Hello Carol Smith!
Uma coisa importante a ser observada no Bash é que aspas duplas e aspas simples ('
) se comportam de maneira muito diferente. As aspas duplas são consideradas “fracas” porque permitem que o intérprete efetue a substituição dentro das aspas. Aspas simples são consideradas “fortes” por impedirem a substituição. Considere o seguinte exemplo:
#!/bin/bash # Este é nosso primeiro comentário. Também é recomendável documentar todos os scripts. username="Carol Smith" echo "Hello $username!" echo 'Hello $username!'
$ ./new_script.sh Hello Carol Smith! Hello $username!
No segundo comando echo
, o intérprete foi impedido de substituir $username
por Carol Smith
, e assim a saída é interpretada literalmente.
Argumentos
Você já aprendeu a usar argumentos nos utilitários principais do Linux. Por exemplo, rm testfile
contém tanto o executável rm
quanto um argumento testfile
. Os argumentos podem ser passados para o script na execução e modificam o comportamento do script. É fácil implementá-los.
#!/bin/bash # Este é nosso primeiro comentário. Também é recomendável documentar todos os scripts. username=$1 echo "Hello $username!"
Em vez de atribuir um valor a username
diretamente dentro do script, atribuímos a ele o valor de uma nova variável $1
. Ela faz referência ao valor do primeiro argumento.
$ ./new_script.sh Carol Hello Carol!
Os nove primeiros argumentos são tratados dessa maneira. Há modos de lidar com mais de nove argumentos, mas isso está fora do alcance desta lição. Eis um exemplo usando apenas dois argumentos:
#!/bin/bash # Este é nosso primeiro comentário. Também é recomendável documentar todos os scripts. username1=$1 username2=$2 echo "Hello $username1 and $username2!"
$ ./new_script.sh Carol Dave Hello Carol and Dave!
Existe uma consideração importante ao usar argumentos: no exemplo acima, temos dois argumentos, Carol
e Dave
, atribuídos a $1
e $2
, respectivamente. Se o segundo argumento estiver ausente, por exemplo, o shell não emitirá uma mensagem de erro. O valor de $2
será simplesmente nulo, ou nada.
$ ./new_script.sh Carol Hello Carol and !
Em nosso caso, seria recomendável introduzir alguma lógica em nosso script para que diferentes condições afetem a saída que desejamos imprimir. Começaremos introduzindo outra variável útil e, em seguida, criaremos declarações if.
Retorno do número de argumentos
Enquanto variáveis como $1
e $2
contêm o valor dos argumentos posicionais, a variável $#
contém o número de argumentos.
#!/bin/bash # Este é nosso primeiro comentário. Também é recomendável documentar todos os scripts. username=$1 echo "Hello $username!" echo "Number of arguments: $#."
$ ./new_script.sh Carol Dave Hello Carol! Number of arguments: 2.
Lógica Condicional
O uso da lógica condicional na programação é um tópico vasto que não será abordado em profundidade nesta lição. Vamos nos concentrar na sintaxe dos condicionais no Bash, que é diferente da maioria das outras linguagens de programação.
Primeiro, vamos rever nosso objetivo. Temos um script simples capaz de imprimir uma saudação para um único usuário. Se houver algo diferente de um único usuário, temos de imprimir uma mensagem de erro.
-
A condição que estamos testando é o número de usuários, que está contido na variável
$#
. Gostaríamos de saber se o valor de$#
é1
. -
Se a condição for verdadeira, a ação executada será saudar o usuário.
-
Se a condição for falsa, imprimiremos uma mensagem de erro.
Agora que a lógica está clara, vamos nos concentrar na sintaxe necessária para implementá-la.
#!/bin/bash # Um script simples para saudar um único usuário. if [ $# -eq 1 ] then username=$1 echo "Hello $username!" else echo "Please enter only one argument." fi echo "Number of arguments: $#."
A lógica condicional está contida entre if
e fi
. A condição a ser testada fica entre colchetes [ ]
e a ação a tomar caso a condição seja verdadeira é indicada após then
. Observe os espaços entre os colchetes e a lógica contida neles. A omissão desses espaços causará erros.
Esse script exibirá a nossa saudação ou a mensagem de erro. Mas ele sempre imprimirá a linha Number of arguments
.
$ ./new_script.sh Please enter only one argument. Number of arguments: 0. $ ./new_script.sh Carol Hello Carol! Number of arguments: 1.
Tome nota da declaração if
. Usamos -eq
para fazer uma comparação numérica. Nesse caso, estamos testando se o valor de $#
é igual a um. As outras comparações que podemos realizar são:
-ne
-
Diferente de
-gt
-
Maior que
-ge
-
Maior que ou igual a
-lt
-
Menos que
-le
-
Menos que ou igual a
Exercícios guiados
-
Um usuário insere o seguinte no shell:
$ PATH=~/scripts $ ls Command 'ls' is available in '/bin/ls' The command could not be located because '/bin' is not included in the PATH environment variable. ls: command not found
-
O que o usuário fez?
-
Qual comando pode combinar o valor atual de
PATH
com o novo diretório~/scripts
?
-
-
Considere o script a seguir. Note que ele usa
elif
para conferir uma segunda condição:> /!bin/bash > fruit1 = Apples > fruit2 = Oranges if [ $1 -lt $# ] then echo "This is like comparing $fruit1 and $fruit2!" > elif [$1 -gt $2 ] then > echo '$fruit1 win!' else > echo "Fruit2 win!" > done
-
As linhas marcadas com um
>
contêm erros. Corrija esses erros.
-
-
Qual será a saída nas seguintes situações?
$ ./guided1.sh 3 0
$ ./guided1.sh 2 4
$ ./guided1.sh 0 1
Exercícios Exploratórios
-
Escreva um script simples que verifique se exatamente dois argumentos são passados. Se for o caso, imprima os argumentos em ordem inversa. Considere o exemplo (nota: seu código pode ser diferente do nosso, mas deve produzir uma saída idêntica):
if [ $1 == $number ] then echo "True!" fi
-
Este código está correto, mas não é uma comparação numérica. Pesquise na internet para descobrir como este código é diferente de usar
-eq
. -
Existe uma variável de ambiente para imprimir o diretório atual. Use
env
para descobrir o nome dessa variável. -
Usando o que aprendeu nas questões 2 e 3, escreva um script curto que aceite um argumento. Se um argumento for passado, confira se ele corresponde ao nome do diretório atual. Se a resposta for sim, imprima
yes
. Caso contrário, imprimano
.
Resumo
Nesta lição, você aprendeu:
-
Como criar e executar scripts simples
-
Como usar um shebang para especificar um intérprete
-
Como definir e usar variáveis dentro de scripts
-
Como lidar com argumentos em scripts
-
Como construir declarações
if
-
Como comparar números usando operadores numéricos
Comandos usados nos exercícios:
echo
-
Imprime uma string na saída padrão.
env
-
Imprime todas as variáveis de ambiente na saída padrão.
which
-
Imprime o caminho absoluto de um comando.
chmod
-
Altera as permissões de um arquivo.
Variáveis especiais usadas nos exercícios:
$1, $2, … $9
-
Contêm argumentos posicionais passados para o script.
$#
-
Contém o número de argumentos passados para o script.
$PATH
-
Contém os diretórios que possuem executáveis usados pelo sistema.
Operadores usados nos exercícios:
-ne
-
Diferente de
-gt
-
Maior que
-ge
-
Maior que ou igual a
-lt
-
Menos que
-le
-
Menos que ou igual a
Respostas aos Exercícios Guiados
-
Um usuário insere o seguinte no shell:
$ PATH=~/scripts $ ls Command 'ls' is available in '/bin/ls' The command could not be located because '/bin' is not included in the PATH environment variable. ls: command not found
-
O que o usuário fez?
O usuário sobrescreveu o conteúdo de PATH com o diretório
~/scripts
. O comandols
não pode mais ser encontrado, já que não está contido em PATH. Note que essa alteração afeta somente a sessão atual; basta se deslogar e se relogar novamente para reverter a mudança. -
Qual comando pode combinar o valor atual de
PATH
com o novo diretório~/scripts
?PATH=$PATH:~/scripts
-
-
Considere o script a seguir. Note que ele usa
elif
para conferir uma segunda condição:> /!bin/bash > fruit1 = Apples > fruit2 = Oranges if [ $1 -lt $# ] then echo "This is like comparing $fruit1 and $fruit2!" > elif [$1 -gt $2 ] then > echo '$fruit1 win!' else > echo "Fruit2 win!" > done
-
As linhas marcadas com um
>
contêm erros. Corrija esses erros.#!/bin/bash fruit1=Apples fruit2=Oranges if [ $1 -lt $# ] then echo "This is like comparing $fruit1 and $fruit2!" elif [ $1 -gt $2 ] then echo "$fruit1 win!" else echo "$fruit2 win!" fi
-
-
Qual será a saída nas seguintes situações?
$ ./guided1.sh 3 0
Apples win!
$ ./guided1.sh 2 4
Oranges win!
$ ./guided1.sh 0 1
This is like comparing Apples and Oranges!
Respostas aos Exercícios Exploratórios
-
Escreva um script simples que verifique se exatamente dois argumentos são passados. Se for o caso, imprima os argumentos em ordem inversa. Considere o exemplo (nota: seu código pode ser diferente do nosso, mas deve produzir uma saída idêntica):
if [ $1 == $number ] then echo "True!" fi
#!/bin/bash if [ $# -ne 2 ] then echo "Error" else echo "$2 $1" fi
-
Este código está correto, mas não é uma comparação numérica. Pesquise na internet para descobrir como este código é diferente de usar
-eq
.Podemos comparar strings com
==
. Ou seja, se os caracteres de ambas as variáveis corresponderem exatamente, a condição é verdadeira.abc == abc
true
abc == ABC
false
1 == 1
true
1+1 == 2
false
A comparação de strings provoca comportamentos inesperados se estivermos testando com números.
-
Existe uma variável de ambiente para imprimir o diretório atual. Use
env
para descobrir o nome dessa variável.PWD
-
Usando o que aprendeu nas questões 2 e 3, escreva um script curto que aceite um argumento. Se um argumento for passado, confira se ele corresponde ao nome do diretório atual. Se a resposta for sim, imprima
yes
. Caso contrário, imprimano
.#!/bin/bash if [ "$1" == "$PWD" ] then echo "yes" else echo "no" fi