Você deseja que seus scripts de shell do Linux lidem com opções e argumentos de linha de comando com mais facilidade? O Bash getopts
integrado permite analisar opções de linha de comando com sutileza – e também é fácil. Nós mostramos-lhe como.
Índice
Apresentando o getopts embutido
Passar valores para um script Bash é uma questão bastante simples. Você chama seu script da linha de comando ou de outro script e fornece sua lista de valores por trás do nome do script. Esses valores podem ser acessados dentro do seu script como variáveis , começando $1
pela primeira variável, $2
pela segunda e assim por diante.
Mas se você quiser passar opções para um script, a situação rapidamente se torna mais complexa. Quando dizemos opções, queremos dizer as opções, sinalizadores ou opções que programas como ls
podem manipular. Eles são precedidos por um traço “ -
” e geralmente atuam como um indicador para o programa ativar ou desativar algum aspecto de sua funcionalidade.
O ls
comando possui mais de 50 opções, principalmente relacionadas à formatação de sua saída. A -X
opção (classificar por extensão) classifica a saída em ordem alfabética por extensão de arquivo . A -U
opção (não classificada) lista por ordem de diretório .
As opções são apenas isso — são opcionais. Você não sabe quais opções – se houver alguma – o usuário vai escolher usar, e também não sabe em que ordem eles podem listá-las na linha de comando . Isso aumenta a complexidade do código necessário para analisar as opções.
As coisas se tornam ainda mais complicadas se algumas de suas opções receberem um argumento, conhecido como argumento de opção , Por exemplo, a ls -w
opção (largura) espera ser seguida por um número, representando a largura máxima de exibição da saída. E, claro, você pode estar passando outros parâmetros em seu script que são simplesmente valores de dados, que não são opções.
Felizmente getopts
lida com essa complexidade para você. E porque é um built-in, está disponível em todos os sistemas que possuem o shell Bash, então não há nada para instalar.
Nota: getopts Não getopt
Existe um utilitário mais antigo chamado getopt
. Este é um pequeno programa utilitário , não um built-in. Existem muitas versões diferentes getopt
com comportamentos diferentes, enquanto o getops
built-in segue as diretrizes POSIX.
digite getopts
digite getopt
Como getopt
não é um built-in, ele não compartilha alguns dos benefícios automáticos que o getopts
faz, como lidar com espaços em branco de maneira sensata. Com getopts
, o shell Bash está executando seu script e o shell Bash está fazendo a análise de opções. Você não precisa invocar um programa externo para lidar com a análise.
A desvantagem é getopts
não lidar com nomes de opções de formato longo e com travessão duplo. Então você pode usar opções formatadas como -w
mas não ” ---wide-format
.” Por outro lado, se você tiver um script que aceite as opções -a
, -b
, e
, -c
getopts
permite combiná-las como -abc
, -bca
, ou -bac
e assim por diante.
Estamos discutindo e demonstrando getopts
neste artigo, portanto, certifique-se de adicionar o “s” final ao nome do comando.
Uma recapitulação rápida: como lidar com valores de parâmetros
Este script não usa opções tracejadas como -a
ou -b
. Ele aceita parâmetros “normais” na linha de comando e estes são acessados dentro do script como valores.
#!/bin/bash # pega as variaveis uma a uma echo "Variável Um: $1" echo "Variável dois: $2" echo "Variável três: $3" # percorre as variáveis for var em " $@" faça echo "$ var" feito
Os parâmetros são acessados dentro do script como variáveis $1
, $2
ou $3
.
Copie este texto em um editor e salve-o como um arquivo chamado “variables.sh”. Precisaremos torná-lo executável com o chmod
comando . Você precisará fazer esta etapa para todos os scripts que discutimos. Basta substituir o nome do arquivo de script apropriado a cada vez.
chmod +x variáveis.sh
Se executarmos nosso script sem parâmetros, obteremos essa saída.
./variables.sh
Não passamos parâmetros para que o script não tenha valores para relatar. Vamos fornecer alguns parâmetros desta vez.
./variables.sh como nerd
Como esperado, as variáveis $1
, $2
, e $3
foram definidas para os valores dos parâmetros e os vemos impressos.
Esse tipo de manipulação de parâmetros um por um significa que precisamos saber com antecedência quantos parâmetros haverá. O loop na parte inferior do script não se importa com quantos parâmetros existem, ele sempre percorre todos eles.
Se fornecermos um quarto parâmetro, ele não será atribuído a uma variável, mas o loop ainda o tratará.
./variables.sh como fazer um site geek
Se colocarmos aspas em torno de duas das palavras, elas serão tratadas como um parâmetro.
./variables.sh como "para geek"
Se precisarmos que nosso script lide com todas as combinações de opções, opções com argumentos e parâmetros de tipo de dados “normais”, precisaremos separar as opções dos parâmetros regulares. Podemos conseguir isso colocando todas as opções — com ou sem argumentos — antes dos parâmetros regulares.
Mas não vamos correr antes de podermos andar. Vejamos o caso mais simples para lidar com opções de linha de comando.
Opções de manuseio
Usamos getopts
em while
loop. Cada iteração do loop funciona em uma opção que foi passada para o script. Em cada caso, a variável OPTION
é definida para a opção identificada por getopts
.
A cada iteração do loop, getopts
passa para a próxima opção. Quando não há mais opções, getopts
retorna false
e o while
loop é encerrado.
A OPTION
variável é comparada com os padrões em cada uma das cláusulas da instrução case. Como estamos usando uma instrução case , não importa a ordem em que as opções são fornecidas na linha de comando. Cada opção é descartada na instrução case e a cláusula apropriada é acionada.
As cláusulas individuais na instrução case facilitam a execução de ações específicas de opções no script. Normalmente, em um script do mundo real, você definiria uma variável em cada cláusula, e isso funcionaria como sinalizadores mais adiante no script, permitindo ou negando alguma funcionalidade.
Copie este texto em um editor e salve-o como um script chamado “options.sh” e torne-o executável.
#!/bin/bash enquanto getopts 'abc' OPÇÃO; Faz caso "$OPTION" em a) echo "Opção a usada" ;; b) echo "Opção b usada" ;; c) echo "Opção c usada" ;; ?) echo "Uso: $(basename $0) [-a] [-b] [-c]" saída 1 ;; esac feito
Esta é a linha que define o loop while.
enquanto getopts 'abc' OPÇÃO; Faz
O getopts
comando é seguido pela string de opções . Isso lista as letras que vamos usar como opções. Apenas letras nesta lista podem ser usadas como opções. Portanto, neste caso, -d
seria inválido. Isso seria capturado pela ?)
cláusula porque getopts
retorna um ponto de interrogação “ ?
” para uma opção não identificada. Se isso acontecer, o uso correto é impresso na janela do terminal:
echo "Uso: $(basename $0) [-a] [-b] [-c]"
Por convenção, colocar uma opção entre colchetes “ []
” neste tipo de mensagem de uso correto significa que a opção é opcional. O comando basename remove qualquer caminho de diretório do nome do arquivo. O nome do arquivo de script é mantido em $0
scripts Bash.
Vamos usar este script com diferentes combinações de linha de comando.
./options.sh -a
./options.sh -a -b -c
./options.sh -ab -c
./options.sh -cab
Como podemos ver, todas as nossas combinações de teste de opções são analisadas e tratadas corretamente. E se tentarmos uma opção que não existe?
./options.sh -d
A cláusula de uso é acionada, o que é bom, mas também recebemos uma mensagem de erro do shell. Isso pode ou não importar para o seu caso de uso. Se você estiver chamando o script de outro script que precisa analisar mensagens de erro, ficará mais difícil se o shell também estiver gerando mensagens de erro.
Desligar as mensagens de erro do shell é muito fácil. Tudo o que precisamos fazer é colocar dois pontos ” :
” como o primeiro caractere da string de opções.
Edite seu arquivo “options.sh” e adicione dois pontos como o primeiro caractere da string de opções, ou salve este script como “options2.sh” e torne-o executável.
#!/bin/bash while getopts ':abc' OPÇÃO; Faz caso "$OPTION" em a) echo "Opção a usada" ;; b) echo "Opção b usada" ;; c) echo "Opção c usada" ;; ?) echo "Uso: $(basename $0) [-a] [-b] [-c]" saída 1 ;; esac feito
Quando executamos isso e geramos um erro, recebemos nossas próprias mensagens de erro sem nenhuma mensagem de shell.
./options2.sh.sh -d
Usando getopts com argumentos de opção
Para dizer getopts
que uma opção será seguida por um argumento, coloque dois pontos ” :
” imediatamente após a letra da opção na string de opções.
Se seguirmos o “b” e o “c” em nossa string de opções com dois pontos, getopt
esperaremos argumentos para essas opções. Copie este script em seu editor e salve-o como “arguments.sh” e torne-o executável.
Lembre-se, os primeiros dois pontos na string de opções são usados para suprimir mensagens de erro do shell – não tem nada a ver com o processamento de argumentos.
Quando getopt
processa uma opção com um argumento, o argumento é colocado na OPTARG
variável. Se você quiser usar esse valor em outro lugar em seu script, precisará copiá-lo para outra variável.
#!/bin/bash while getopts ':ab:c:' OPÇÃO; Faz caso "$OPTION" em a) echo "Opção a usada" ;; b) argB="$OPTARG" echo "Opção b usada com: $argB" ;; c) argC="$OPTARG" echo "Opção c usada com: $argC" ;; ?) echo "Uso: $(basename $0) [-a] [-b argumento] [-c argumento]" saída 1 ;; esac feito
Vamos executar isso e ver como funciona.
./arguments.sh -a -b "como nerd" -c reviewgeek
./arguments.sh -c reviewgeek -a
Portanto, agora podemos lidar com opções com ou sem argumentos, independentemente da ordem em que são fornecidas na linha de comando.
Mas e os parâmetros regulares? Dissemos anteriormente que sabíamos que teríamos que colocá-los na linha de comando após qualquer opção. Vamos ver o que acontece se o fizermos.
Opções e parâmetros de mistura
Vamos mudar nosso script anterior para incluir mais uma linha. Quando o while
loop for encerrado e todas as opções tiverem sido tratadas, tentaremos acessar os parâmetros regulares. Vamos imprimir o valor em $1
.
Salve este script como “arguments2.sh” e torne-o executável.
#!/bin/bash while getopts ':ab:c:' OPÇÃO; Faz caso "$OPTION" em a) echo "Opção a usada" ;; b) argB="$OPTARG" echo "Opção b usada com: $argB" ;; c) argC="$OPTARG" echo "Opção c usada com: $argC" ;; ?) echo "Uso: $(basename $0) [-a] [-b argumento] [-c argumento]" saída 1 ;; esac feito echo "A variável um é: $1"
Agora vamos tentar algumas combinações de opções e parâmetros.
./arguments2.sh dave
./arguments2.sh -a dave
./arguments2.sh -a -c how-to-geek dave
Então agora podemos ver o problema. Assim que qualquer opção é usada, as variáveis $1
em diante são preenchidas com os sinalizadores de opção e seus argumentos. No último exemplo, $4
manteria o valor do parâmetro “dave”, mas como você acessa isso em seu script se não sabe quantas opções e argumentos serão usados?
A resposta é usar OPTIND
e o shift
comando.
O shift
comando descarta o primeiro parâmetro — independentemente do tipo — da lista de parâmetros. Os outros parâmetros são “shuffle down”, então o parâmetro 2 se torna o parâmetro 1, o parâmetro 3 se torna o parâmetro 2 e assim por diante. E assim $2
se torna $1
, $3
se torna $2
, e assim por diante.
Se você fornecer shift
um número, essa quantidade de parâmetros será retirada da lista.
OPTIND
conta as opções e argumentos à medida que são encontrados e processados. Uma vez que todas as opções e argumentos tenham sido processados OPTIND
, será um número maior que o número de opções. Então, se usarmos shift para cortar (OPTIND-1)
parâmetros da lista de parâmetros, ficaremos com os parâmetros regulares em $1
diante.
É exatamente isso que esse script faz. Salve este script como “arguments3.sh” e torne-o executável.
#!/bin/bash while getopts ':ab:c:' OPÇÃO; Faz caso "$OPTION" em a) echo "Opção a usada" ;; b) argB="$OPTARG" echo "Opção b usada com: $argB" ;; c) argC="$OPTARG" echo "Opção c usada com: $argC" ;; ?) echo "Uso: $(basename $0) [-a] [-b argumento] [-c argumento]" saída 1 ;; esac feito echo "Antes - variável um é: $1" shift "$(($OPTIND -1))" echo "Depois - variável um é: $1" echo "O resto dos argumentos (operandos)" para x em "$@" Faz eco $ x feito
Vamos executar isso com uma mistura de opções, argumentos e parâmetros.
./arguments3.sh -a -c how-to-geek "dave dee" dozy beaky mick tic
Podemos ver que antes de chamarmos shift
, $1
seguramos “-a”, mas depois que o comando shift $1
mantém nosso primeiro parâmetro não-opção, não-argumento. Podemos percorrer todos os parâmetros tão facilmente quanto em um script sem análise de opções.
É sempre bom ter opções
Manipular opções e seus argumentos em scripts não precisa ser complicado. Com getopts
você pode criar scripts que lidam com opções de linha de comando, argumentos e parâmetros exatamente como scripts nativos compatíveis com POSIX deveriam.