Passando argumentos para um script

Passando argumentos para um script

Estou fazendo o curso Linux Essentials e estava indo bem até chegar ao capítulo de scripts. Eu simplesmente não entendo esses conceitos. Me perguntando se alguém pode dividir o seguinte em termos ultra simplistas ou me indicar uma referência melhor para aprender. Atualmente estou usando o currículo do netacad.


Do livro didático (com pequenas alterações de formatação):

Existem algumas variáveis ​​especiais além daquelas que você definiu. Você pode passar argumentos para o seu script:

#!/bin/bash
echo "Hello $1"

Um cifrão seguido por um número N corresponde ao enésimo argumento passado ao script. Se você chamar o exemplo acima com ./test.sha saída será Hello Linux. A $0variável contém o nome do próprio script.

Depois que um programa é executado, seja um binário ou um script, ele retorna um código de saída que é um número inteiro entre 0 e 255. Você pode testar isso por meio da $?variável para ver se o comando anterior foi concluído com êxito.


Eu entendo como atribuir variáveis ​​e como elas funcionam com o $mas todo o problema com $0e $1- simplesmente não entendo.

Qualquer ajuda seria muito apreciada.

Responder1

A descrição do livro está errada (ou pelo menos faltando alguma coisa). Para fazer com que esse script imprima "Hello Linux", você deve executá-lo assim:

./test.sh Linux

Se você executá-lo com just ./test.sh, ele imprimirá apenas "Hello", porque não houve primeiro argumento e $1não está definido. Por outro lado, suponha que você executou assim:

./test.sh foo bar baz

então, dentro do script, $0seria "./test.sh", $1seria "foo", $2seria "bar" e $3seria "baz".

Quanto a $?, considere o seguinte trecho de script:

ls nonexistentfile.txt
echo "The exit status of ls was: $?"
echo "The exit status of echo (the first one) was: $?"

Quando executado, isso imprimirá algo como:

ls: nonexistentfile.txt: No such file or directory
The exit status of ls was: 1
The exit status of echo (the first one) was: 0

O lscomando não pode listar nonexistentfile.txt (porque ele não existe), então ele imprime uma mensagem de erro nesse sentido e sai com um status diferente de zero para indicar que algo deu errado. O primeiro echocomando imprime esse status de saída ( $?) e, como faz isso com sucesso, sai com status zero. Quando o segundo echocomando é executado, ele vem $?do primeiro echocomando e imprime "0".

Aliás, muitos comandos usam apenas status de saída 0 (sucesso) ou 1 (algum tipo de falha), mas alguns usam diferentes status de falha para indicar exatamente o que deu errado. Aqui está um trecho docurlpágina de manual:

EXIT CODES
       There are a bunch of different  error  codes  and  their  corresponding
       error  messages  that  may appear during bad conditions. At the time of
       this writing, the exit codes are:

       1      Unsupported protocol. This build of curl has no support for this
              protocol.

       2      Failed to initialize.

       3      URL malformed. The syntax was not correct.

       ...

       88     FTP chunk callback reported error

       89     No connection available, the session will be queued

       90     SSL public key does not matched pinned public key

       91     Invalid SSL certificate status.

       92     Stream error in HTTP/2 framing layer.

... portanto, um script usado curlpoderia verificar $?o que deu errado e responder de maneira diferente dependendo do problema.

Responder2

$0é o nome que você usa para executar o script. $1, $2e assim por diante são os parâmetros posicionais do script, que contêm os valores dos argumentos de linha de comando que você passou ao executar o script.

ComoGordon Davisson disse, o autor do livro deve ter querido dizer que correr ./test Linuximprimiria Hello Linux. Quando você faz isso, ./testvai para o parâmetro especial 0e Linuxvai para o primeiro parâmetro posicional 1. O script expande esse primeiro parâmetro posicional precedendo-o com um cifrão ( $1), assim como você faz com variáveis. Se você tivesse executado ./test Hello Linux for Human Beings, no script, $1expandiria para Linux, $2para for, $3para Humane $4para Beings.

Você pode escrever um script simples para testar isso:

#!/bin/bash

echo "\$0 expands to '$0'."
echo "\$1 expands to '$1'."
echo "\$2 expands to '$2'."
echo "\$3 expands to '$3'."

(Vá até onde quiser. Para parâmetros posicionais maiores que 9, use a ${ }forma de expansão de parâmetros, por exemplo, expanda 10escrevendo ${10}. Em scripts que trabalham com muitos parâmetros posicionais, o parâmetro especial @é frequentemente usado, evitando repetição, mas você pode ignore isso por enquanto, se quiser.)

Tente salvar isso em um arquivo e marcar o arquivo como executável, o que você pode fazer executando chmod +x simplewhere simpleé substituído pelo nome do arquivo, se for diferente. Então você pode executá-lo usando comandos como ./simple, ./simple foo, ./simple foo bare assim por diante.

Você notará que quando menos de três argumentos de linha de comando são passados, os parâmetros posicionais que correspondem àqueles que não foram passados ​​se expandem para a string vazia. Isso é o que acontece quando você tenta expandir um parâmetro de shell que não está definido. Você notará, ainda, que quando mais argumentos de linha de comando são passados, aqueles após o terceiro não são usados. Provavelmente é isso que você esperaria, já que o script não se refere a eles.

Agora tente correr ./simple *. O shell se expande *para todos os nomes de arquivos no diretório atual, exceto aqueles que começam com ., portanto, três deles serão mostrados como os três primeiros parâmetros posicionais (ou menos, se não houver tantos). Você pode tentar executá-lo com outras expansões de shell, como ./simple {5..10}.

Você pode passar argumentos de linha de comando contendo espaços em branco, colocando-os entre aspas. Por exemplo, tente ./simple 'foo bar' baz. Observe que isso $1se expande para foo bareste momento, e não apenas para foo.

Porque o shell executavárias expansões, nem sempre é óbvio quantos argumentos de linha de comando você está passando para um comando. Uma maneira fácil de ver qual será cada argumento é substituir o comando por printf '[%s]\n'. Por exemplo:

$ printf '[%s]\n' f*
[fonts]
[fstab]
[fuse.conf]
[fwupd]
$ printf '[%s]\n' {1,3}{a..c}
[1a]
[1b]
[1c]
[3a]
[3b]
[3c]

Como você iniciou recentemente o script de shell, oManual de referência do Bashpode ser desafiador e talvez você não queira lê-lo do início ao fim. Mas acho que é um recurso valioso, mesmo que você se considere um iniciante. Você pode encontrar a seção emparâmetros de shellútil, pois começa com o que você já sabe - variáveis ​​​​de shell - e passa para parâmetros especiais como ?(que as pessoas costumam chamar de $?parâmetro, já que é assim que você o expande). Para aprendizado geral sobre Bash, especialmente em um nível mais introdutório, recomendoestas páginas, IncluindoGuia Bash.

Responder3

Um bom livro que você deve conhecer é "The Linux Command Line" de William Shotts, publicado pela No Starch Press e disponível como um PDF gratuito no site.site do autor.

Em cada script de shell, há uma coleção de variáveis ​​numeradas, geralmente chamadas de $1, $2, etc. Esses são os "parâmetros posicionais", mais comumente conhecidos como argumentos de linha de comando. Você pode pensar nelas como variáveis ​​​​nomeadas 1, 2, etc. e para obter seus valores, você usaria $1, $2, etc. Quando você chama um script nomeado my_scriptpor meio da linha de comando ./my_script a b c, ele obteria três argumentos que são armazenados nas três variáveis $1​​, $2, e $3. Você não pode atribuir a essas variáveis ​​(exceto como um grupo), mas pode examinar e usar seus valores. Por exemplo, echo "$1"imprimiria o primeiro argumento do seu script.

$0é um pouco incomum; é o nome pelo qual o script que você está executando foi chamado. No caso acima, teria o valor ./my_script. Novamente, você pode ver seu valor, mas não alterá-lo.

$?é o "status de saída" do comando que acabou de ser executado. Se o comando for bem-sucedido, seu status de saída será 0; caso contrário, será um pequeno número inteiro positivo. Você pode comparar $?com zero para ver se o comando anterior foi bem-sucedido ou falhou. Por exemplo, as duas linhas de comando a seguir executarão o grepcomando e, em seguida, ecoarão <1>porque grepfalhou e sairam com um status de 1(indicando que falhou).

grep blarg /etc/passwd
echo "<$?>"

O status de saída é útil para escrever scripts simples como:

#!/bin/bash
# grep_pw: grep for a pattern in /etc/passwd
grep "$1" /etc/passwd
if [[ $? = 0 ]] ;then
  echo "Found it"
  exit 0
else
  echo "Unable to find the pattern '$1' in /etc/passwd"
  exit 1
fi

Coloque esse texto em um arquivo chamado grep_pw, altere-o para ser executável com chmod 700 grep_pwe chame-o ./grep_pw nologinpara encontrar as linhas /etc/passwdque contêm a string nologin.

Quando aprendi sobre o shell, achei o script a seguir inestimável para entender como o shell analisa as linhas de comando e, conseqüentemente, quais argumentos de linha de comando seriam passados ​​para um script.

#!/bin/bash
# echoargs: print all the arguments
counter=1
for a in "$@" ;do
   echo "arg $counter=<$a>"
   let counter=counter+1
done

Coloque esse conteúdo em um arquivo chamado echoargs, altere-o para executável chmod 700 echoargse chame-o como: ./echoargs a "b c" d.

informação relacionada