Introdução ao Bash Shell

Olá pessoal. Esta é uma tradução do RedHat RHCE Exam Preparation Book. Na minha opinião, é muito acessível sobre o básico do bash.

Os scripts de shell são uma ciência em si. Sem entrar em detalhes de tudo o que acontece "oculto", você aprenderá como usar os elementos básicos para escrever seus próprios scripts e analisar o que acontece nos scripts de shell de terceiros.



Compreendendo os elementos básicos dos scripts de shell


De fato, um shell script é uma lista de comandos executados seqüencialmente, além de alguma lógica que permite que o código seja executado apenas sob determinadas condições.

Para entender scripts shell complexos, é recomendável que você comece com scripts básicos.

O seguinte é um script muito simples:

#!/bin/bash # # #This is a script that greets the world # Usage: ./hello clear echo hello world exit 0 

Ele contém vários elementos que devem ser usados ​​em todos os scripts. Para iniciantes, há shebang - esta é a linha #! / Bin / bash. Quando o script é iniciado a partir do shell pai, ele abre um subshell no qual os comandos especificados no script são executados.

Esses comandos podem ser interpretados de várias maneiras. Para entender exatamente como eles devem ser interpretados, o shebang é usado. No exemplo acima, shebang deixa claro que o script deve ser executado pelo shell bash.

Outras conchas também podem ser indicadas. Por exemplo, se seu script contiver código Perl, shebang deve ser #! / Usr / bin / perl. Iniciar um script com shebang é uma boa prática; se omitido, o código do script será executado pelo mesmo shell usado para executar o script.

Imediatamente após o shebang, há uma parte explicando sobre o que é o script. Algumas linhas de comentário no início de cada cenário são uma boa ideia. Em um script curto, muitas vezes é óbvio o que ele faz, mas, à medida que o script fica mais longo e à medida que mais pessoas se envolvem em escrevê-lo e apoiá-lo, fica menos claro o que os autores pretendem fazer.

Para evitar essa situação, adicione linhas de comentário começando com cada caractere #. Os comentários podem estar não apenas nas primeiras linhas, mas também no início de cada subseção do script. Isso certamente ajudará se você ler seu script em alguns meses!

Você também pode comentar não apenas em subseções, mas também em linhas individuais.

Independentemente da posição em que é usado, tudo, desde o caractere # até o final da linha, é um comentário.

Após o bloco de comentários, o corpo do script está localizado. No exemplo acima, esses são vários comandos que são executados seqüencialmente. O corpo do script de shell pode aumentar à medida que se desenvolve.

No final do script, incluí a instrução exit 0 . A instrução exit informa ao shell pai se o script foi bem-sucedido. O estado de saída do último comando no script é o estado de saída do próprio script, a menos que a saída 0 seja usada no final do script.

É útil saber que você pode trabalhar com exit para informar ao shell pai como foram as coisas.
Introduzido no shell pai, o echo $? permite consultar o status de saída do último script em execução.
Após criar o script, verifique se ele pode ser executado. A maneira mais comum de fazer isso é aplicar um pouco de execução a ele. Portanto, se o nome do arquivo de script for hello, use o comando chmod + x ./hello para torná-lo executável.

O script também pode ser executado como um argumento para o comando bash. Nesse caso, digite bash ./hello para executar o script hello. Se o script for executado como um argumento para o comando bash, o arquivo de script não precisará ser executável.

De fato, você pode armazenar o script em qualquer lugar, mas se você quiser armazená-lo em um diretório que não esteja incluído na variável $ PATH, será necessário executá-lo com ./ na frente do nome do script.

Digite ./hello para executar o script ou coloque-o no diretório padrão incluído na variável $ PATH, por exemplo, / usr / local / bin.

Você também pode colocar o script no diretório / bin, após o qual basta digitar o nome do arquivo em qualquer lugar do sistema de arquivos e o script será executado.

Exemplo

Usando vi / bin / datetime, crie um arquivo chamado datetime no diretório / bin. Cole este conteúdo no arquivo criado:

 #!/bin/bash #    .     ,      date who 

Depois de salvar o arquivo, digite chmod + x / bin / datetime para dar permissão ao arquivo para executar. Por exemplo, mude para o diretório inicial usando o comando cd ~ e digite simplesmente datetime .

Vá, por exemplo, para o diretório inicial do cd ~ e insira datetime.

 [root@localhost ~]# datetime Sat Sep 28 00:33:41 EDT 2019 root tty1 2019-09-25 20:28 root pts/0 2019-09-27 20:07 (comp.corp.domain.ru) 

Usando variáveis ​​e entradas


Os scripts bash são muito mais do que apenas uma lista de comandos executados sequencialmente. Uma das coisas boas sobre scripts é que eles podem trabalhar com variáveis ​​e entradas para tornar o script flexível. Nesta seção, você aprenderá como trabalhar com eles.

Usando parâmetros posicionais


Ao executar o script, você pode usar os argumentos. Um argumento é tudo o que você coloca atrás de um comando de script. Argumentos podem ser usados ​​para tornar o script mais flexível. Pegue o comando useradd lisa . Neste exemplo, o comando é useradd e seu argumento, lisa , indica o que precisa ser feito.

Como resultado desse comando, um usuário chamado lisa deve ser criado.

No script, o primeiro argumento é $ 1 , o segundo é $ 2. A Listagem 1 mostra como os argumentos podem ser usados. Tente executar esse código especificando nomes de usuários como parâmetros.

Listagem 1

 #!/bin/bash # run this script with a few arguments echo The first argument is $1 echo The second argument is $2 echo The third argument is $3 

Parâmetros significam entrada de dados antes de executar o script. Nesse caso, especifiquei lisa , lori e bob como parâmetros após o argumento script name:

 [root@server1 ~]# ./argument lisa lori bob The first argument is lisa The second argument is lori The third argument is bob [root@server1 ~]# 

Se você tentou executar o código de amostra, poderá notar que seu conteúdo não é perfeito. Se você usar três argumentos ao executar o script da Lista 1, ele funcionará perfeitamente. Se você usar apenas dois argumentos, o terceiro será gerado sem o valor $ 3.

Se você usar quatro argumentos, o quarto valor (que será armazenado em US $ 4) nunca será exibido. Portanto, se você quiser usar argumentos, é melhor usar uma abordagem mais flexível.

Listagem 2

 #!/bin/bash # run this script with a few arguments echo you have entered $# arguments for i in $@ do echo $i done exit 0 

A Listagem 2 mostra dois novos elementos relacionados aos argumentos:

  • $ # É um contador que mostra quantos argumentos foram usados ​​ao executar o script.
  • $ @ É uma lista de todos os argumentos que foram usados ​​ao executar o script.

Para listar os argumentos que foram usados ​​ao executar esse script, o loop for é usado. Nos loops for , as instruções são executadas desde que a condição seja verdadeira. Nesse cenário, a condição para i em $ @ significa "para cada argumento". Cada vez que o script passa pelo loop, o valor da variável $ @ é atribuído à variável $ i .

Portanto, desde que haja argumentos, o corpo do script é executado.

O corpo do loop for sempre começa com do e fecha done , e os comandos a serem executados são listados entre essas duas palavras-chave. Portanto, o script de exemplo usará eco para exibir o valor de cada argumento e parar quando não houver mais argumentos disponíveis.

Vamos tentar o script na Listagem 2 neste exemplo:

  1. Digite vi argumento para criar o arquivo de argumento e copie o conteúdo do script na Listagem 2 para este arquivo.
  2. Salve o arquivo e torne-o executável.
  3. Execute o comando ./argument abc . Você verá que três linhas são exibidas.
  4. Execute o comando ./argument abcdef . Você verá que, além de abc, de f também será exibido.

Variáveis


Uma variável é um rótulo usado para indicar um local específico na memória que contém um valor específico. As variáveis ​​podem ser definidas estaticamente usando NAME = value ou dinamicamente. Existem duas soluções para definir dinamicamente uma variável:

  • Use a palavra-chave read em um script para solicitar dados do usuário que está executando o script.
  • Use substituição de comando para usar o resultado do comando e atribuí-lo a uma variável. Por exemplo, a data do comando +% d-% m-% y mostra a data atual no formato dia-mês-ano. Para fazer isso em um script, você pode usar HOJE = $ (data +% d-% m-% y) . Para substituir comandos, basta colocar o comando cujo resultado você deseja usar entre os colchetes.

Na seção anterior sobre parâmetros posicionais, você aprendeu como atribuir argumentos a variáveis ​​ao executar um script. Em alguns casos, pode ser mais eficiente solicitar informações quando você achar que algo substancial está faltando. O script abaixo mostra como fazer isso.

Listagem 3. Script de amostra usando o comando read

 #!/bin/bash if [ -z $1 ]; then echo enter a text read TEXT else TEXT=$1 fi echo you have entered the text $TEXT exit 0 

No script da Listagem 3, o operador if ... then ... else ... fi é usado para testar a existência do argumento $ 1 . Isso é feito usando test (test é um comando separado). O comando test pode ser escrito de duas maneiras *: test ou [...] . No exemplo, a linha se [-z $ 1] ... é executada para ver o teste (marque) -z $ 1 .

* - na verdade, três fontes (aprox. Tradutor)

O teste -z verifica se $ 1 existe ou não. Em outras palavras, a linha se [-z $ 1] verifica se $ 1 está vazio, o que significa que nenhum argumento foi fornecido quando esse script foi executado. Nesse caso, os comandos após a instrução then são executados.

Observe que, ao escrever o comando de teste com colchetes, é importante usar espaços após o colchete de abertura e antes do colchete de fechamento, sem espaços, o comando não funcionará.

Observe que a instrução then segue imediatamente o teste . Isso é possível porque um ponto-e-vírgula (;) é usado. O ponto e vírgula é um separador de comandos e pode substituir uma nova linha em um script.

A instrução then executa dois comandos: o comando echo , que exibe a mensagem na tela, e o comando read .

O comando read para o script para que a entrada do usuário possa ser processada e armazenada na variável TEXT. Portanto, ler TEXT coloca toda a entrada do usuário na variável TEXT, que será usada posteriormente no script.

A próxima parte é representada pela instrução else . Os comandos após a instrução else são executados em todos os outros casos, o que nesse caso significa "caso contrário, se o argumento foi fornecido". Nesse caso, a variável TEXT é determinada e o valor atual de $ 1 é atribuído a ela.

Observe como a variável é definida: imediatamente após o nome da variável, existe um sinal = seguido de $ 1. Observe que você nunca deve usar espaços ao definir variáveis.

Então, as condições if são fechadas usando o operador fi . Após a conclusão da condição if, você tem certeza de que a variável TEXT está definida e possui um valor. A penúltima linha do script lê o valor da variável TEXT e mapeia esse valor para STDOUT usando o comando echo . Observe que, para solicitar o valor atual de uma variável, ele se refere ao nome da variável, começando com o sinal $ à frente.

Você pode praticar usando este exemplo ao trabalhar com entrada.

  1. Abra o editor e crie um arquivo chamado texto. Digite o conteúdo do código na Listagem 3 neste arquivo.
  2. Escreva o arquivo no disco e execute chmod + x text para torná-lo executável.
  3. Execute o script executando ./text e sem argumentos adicionais. Você verá que ele pede entrada.
  4. Execute o script usando " hello " como argumento (./text hello). O resultado exibirá "você inseriu o texto hello" em STDOUT.

Usando condições e loops


Como você já viu, instruções condicionais podem ser usadas em um script. Essas instruções condicionais são executadas apenas se uma determinada condição for atendida.

Existem várias instruções e loops condicionais no bash que são frequentemente usados.

  • if ... then ... else - usado para executar código se uma determinada condição for atendida
  • for - usado para executar comandos para um intervalo de valores
  • while - usado para executar código se uma determinada condição for atendida
  • before - usado para executar o código até que uma determinada condição seja atendida
  • case - usado para avaliar um número limitado de valores específicos

se então mais


A construção if then else é comum para avaliar condições específicas. Você já viu um exemplo com ele. Essa declaração condicional é frequentemente usada com o comando test . Este comando permite verificar muitas coisas: por exemplo, não apenas se um arquivo existe, mas também comparar arquivos, comparar números inteiros e muito mais.
Você pode aprender mais sobre teste na referência com o comando man test.

O básico se construir é se ... então ... fi .

Ele compara uma condição, conforme mostrado no exemplo a seguir:

 if [ -z $1 ] then echo no value provided fi 

Na Listagem 3, você viu como pode avaliar duas condições, incluindo outras em uma expressão. A Listagem 4 mostra como avaliar várias condições de se para outro . Isso é útil se você precisar verificar muitos valores diferentes.

Observe que este exemplo também usa vários comandos de teste .

Listagem 4 . Exemplo com if then else

 #!/bin/bash # run this script with one argument # the goal is to find out if the argument is a file or a directory if [ -f $1 ] then echo "$1 is a file" elif [ -d $1 ] then echo "$1 is a directory" else echo "I do not know what \$1 is" fi exit 0 

|| e &&


Em vez de escrever instruções completas if ..., você pode usar os operadores lógicos || bem como && . || é um "OR" lógico e executará a segunda parte da instrução somente se a primeira parte não for verdadeira; && é um "AND" lógico e executará a segunda parte da declaração somente se a primeira parte for verdadeira.

Considere estas duas linhas:

 [ -z $1 ] && echo no argument provided 

 ping -c 1 8.8.8.8 2>/dev/null || echo node is not available 

O primeiro exemplo verifica se $ 1 está vazio. Se esta verificação estiver correta (o que basicamente significa que o comando termina com o código de saída 0), o segundo comando é executado.

No segundo exemplo, o comando ping é usado para verificar a disponibilidade do host.
Este exemplo usa um "OR" lógico para exibir o texto "o nó não está disponível" no caso de uma falha no comando ping .

Você encontrará isso frequentemente, em vez da instrução if condicional, && e || . No exercício abaixo, você pode praticar o uso de instruções condicionais usando if ... then ... else , ou && e || .

Exercício . Usando if ... then ... else

Neste exercício, você trabalhará em um script que verifica o que é um arquivo e o que é um diretório.

  1. Inicie o editor e crie um script chamado filechk.
  2. Copie o conteúdo da Listagem 4 neste script.
  3. Execute alguns testes com ele, como ./filechk / etc / hosts , ./filechck / usr , ./filechk arquivo não existente .

For loop


O loop for é uma ótima solução para o processamento de intervalos de dados. Na Listagem 5, você pode ver o primeiro exemplo com for , onde o intervalo é determinado e processado enquanto houver valores brutos nesse intervalo.

Listagem 5

 #!/bin/bash # for (( COUNTER=100; COUNTER>1; COUNTER-- )); do echo $COUNTER done exit 0 

Um loop for sempre começa com a palavra-chave for, seguida por uma condição que precisa ser verificada. Isso é seguido pela palavra-chave do, seguida pelos comandos que devem ser executados; se a condição for verdadeira, o loop será finalizado usando a palavra - chave done .

No exemplo da Listagem 5, é possível ver que a condição é um intervalo de números entre parênteses designados à variável COUNTER.

Uma pequena explicação

As expressões aritméticas internas ((...)) são calculadas e seu resultado é retornado. Por exemplo, no caso mais simples, a construção a = $ ((5 + 3)) atribuirá à variável "a" o valor da expressão "5 + 3" ou 8. Além disso, parênteses duplos permitem trabalhar com variáveis ​​no estilo da linguagem C.

Primeiro, a variável é inicializada para 100 e, desde que o valor seja maior que 1, é subtraído 1. A cada iteração, desde que a condição seja verdadeira, o valor da variável $ COUNTER é exibido usando o comando echo .

Na Listagem 6, você pode ver uma das minhas frases favoritas com for . O intervalo é definido desta vez como uma sequência de números, começando de 100 e chegando a 104.

Listagem 6

 for i in {100..104}; do ping –c 1 192.168.4.$i >/dev/null && echo 192.168.4.$i is up; done 

Observe como o intervalo é determinado: primeiro você especifica o primeiro número, depois dois pontos e indica o último número no intervalo. Além disso, com for i in, para cada um desses números, a variável i é atribuída. Cada um desses números é atribuído à variável ie o comando ping é executado, em que a opção -c 1 garante que apenas uma solicitação seja enviada.

O resultado do comando ping não é levado em consideração, portanto sua saída é redirecionada para / dev / null. Com base no status de saída do comando ping , uma parte da expressão && é executada. Portanto, se o host estiver disponível, uma linha será exibida indicando que está em execução.

Entendendo enquanto e até


Se a instrução for que você acabou de ler for útil para trabalhar com intervalos de elementos, a instrução while será útil quando você desejar rastrear algo como acessibilidade do processo. Há também uma instrução até , que é executada desde que a condição sendo verificada seja falsa. Na Listagem 7, você pode ler como while é usado para monitorar a atividade do processo.
Nota Eu não entendi o que esse script faz. No meu caso, o CentOS 7 é usado e, por padrão, não há monitor, embora o script diga explicitamente:
  uso: monitor <nome do processo> 
Em algum lugar por meia hora, pesquisei no Google o programa de monitoramento do CetOS, mas não o encontrei. E geralmente não está claro qual monitor lateral está aqui se o ps aux for usado. De qualquer forma, não entendi o que esse script faz. Uma grande solicitação para ajudar a resolver esse problema é ajustar o texto e / ou script.
Listagem 7

 #!/bin/bash # # usage: monitor <processname> while ps aux | grep $1 | grep -v grep > /dev/tty11 do sleep 5 done clear echo your process has stopped logger $1 is no longer present mail -s "process $1 has stopped" root < . 

O script na Listagem 7 consiste em duas partes. Primeiro, há um loop while . Em segundo lugar, há tudo o que precisa ser feito quando o loop while não é mais avaliado como verdadeiro.

O núcleo do loop while é o comando ps , que tem um valor de $ 1 .

Observe o uso de grep -v grep , que exclui as linhas que contêm o comando grep do resultado. Lembre-se de que o comando ps incluirá todos os processos em execução, incluindo o comando grep , para os quais a saída do comando ps é passada. Isso pode levar a uma correspondência positiva falsa.

A saída do comando ps aux é redirecionada para / dev / tty11. Isso permite que você leia os resultados de tty11 posteriormente, se necessário, mas eles não são exibidos por padrão.

while , , . sleep 5 , 5 .

while , . ( , ), , .

, . mail -s “process $1 has stopped” root < . root , Linux*. mail , -s .

* — CentOS . (. )

< . .

mail , . , , . STDIN. - .

whileuntil , 8. until , , .

8 users $1 , . , . , , until .

8

 #!/bin/bash # until users | grep $1 > /dev/null do echo $1 is not logged in yet sleep 5 done echo $1 has just logged in mail -s "$1 has just logged in" root < . 

case


case *. case . , case Linux, .

* — ?

case , , , .

9 case , .

9

 case "$1" in start) start;; stop) rm -f $lockfile stop;; restart) restart;; reload) reload;; status) status ;; *) echo "Usage: $0 (start|stop|restart|reload|status)" ;; esac 

O gabinete possui vários recursos. Primeiro vem a linha - caso em sequência . Isto é seguido por uma lista de todos os valores possíveis que precisam ser avaliados. Cada elemento é fechado com um colchete ) .

Isto é seguido por uma lista de comandos a serem executados se um argumento específico foi usado. A lista de comandos é fechada com ponto e vírgula duplo ;; pode ser usado imediatamente após o último comando e pode ser usado em uma linha separada.

Observe também que *) se aplica a todos os outros parâmetros não especificados anteriormente. Este é um operador abrangente.

O loop de iteração do caso termina com a instrução esac .

Observe que as seqüências no caso são executadas em ordem. Quando a primeira correspondência é feita, a declaração do caso não avalia nada.

Como parte da avaliação, modelos semelhantes ao modelo podem ser usados. Isso é mostrado em *) uma sequência que corresponde a tudo. Mas você também pode usar sequências como start | Start | START) para combinar com outro caso .

Depurando scripts no Bash


, , . , bash -x . , , , .

10 bash -x , , grep , , .

 [root@server1 ~]# bash -x 319.sh + grep Usage: grep [OPTION]... PATTERN [FILE]... Try 'grep --help' for more information. + users + echo is not logged in yet is not logged in yet + sleep 5 


, . , .

Source: https://habr.com/ru/post/pt471242/


All Articles