![Passando argumentos para um script](https://rvso.com/image/913177/Passando%20argumentos%20para%20um%20script.png)
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.sh
a saída será Hello Linux. A$0
variá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 $0
e $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 $1
não está definido. Por outro lado, suponha que você executou assim:
./test.sh foo bar baz
então, dentro do script, $0
seria "./test.sh", $1
seria "foo", $2
seria "bar" e $3
seria "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 ls
comando 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 echo
comando imprime esse status de saída ( $?
) e, como faz isso com sucesso, sai com status zero. Quando o segundo echo
comando é executado, ele vem $?
do primeiro echo
comando 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 docurl
pá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 curl
poderia 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
, $2
e 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 Linux
imprimiria Hello Linux
. Quando você faz isso, ./test
vai para o parâmetro especial 0
e Linux
vai 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, $1
expandiria para Linux
, $2
para for
, $3
para Human
e $4
para 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 10
escrevendo ${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 simple
where simple
é substituído pelo nome do arquivo, se for diferente. Então você pode executá-lo usando comandos como ./simple
, ./simple foo
, ./simple foo bar
e 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 $1
se expande para foo bar
este 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_script
por 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 grep
comando e, em seguida, ecoarão <1>
porque grep
falhou 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_pw
e chame-o ./grep_pw nologin
para encontrar as linhas /etc/passwd
que 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 echoargs
e chame-o como: ./echoargs a "b c" d
.