Como usar getopts para analisar opções de script de shell do Linux
Publicados: 2022-06-25 Você deseja que seus scripts de shell do Linux lidem com opções e argumentos de linha de comando com mais facilidade? O getopts
integrado do Bash permite analisar opções de linha de comando com sutileza - e também é fácil. Nós mostramos-lhe como.
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 de seu script como variáveis, começando com $1
para a primeira variável, $2
para a 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 comando ls
possui mais de 50 opções, principalmente relacionadas à formatação de sua saída. A opção -X
(classificar por extensão) classifica a saída em ordem alfabética por extensão de arquivo. A opção -U
(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 ele pode 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 opção ls -w
(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, o 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 do getopt
com comportamentos diferentes, enquanto o getops
embutido 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
oferece, como lidar com espaços em branco de forma 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 é que getopts
não lida com nomes de opções de formato longo e travessão duplo. Portanto, 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.
RELACIONADO: Como escapar de espaços em caminhos de arquivo na linha de comando do Windows
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 para 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 comando chmod
. 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 um loop while
. 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 loop while
é encerrado.
A variável OPTION
é 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 elas atuariam 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 comando getopts
é 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
em 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 ao 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 “c” em nossa string de opções com dois pontos, getopt
esperará 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 variável OPTARG
. 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 loop while
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
conteria o valor do parâmetro “dave”, mas como você acessa isso em seu script se você não sabe quantas opções e argumentos serão usados?
A resposta é usar OPTIND
e o comando shift
.
O comando shift
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
com 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. Portanto, se usarmos os parâmetros shift to trim (OPTIND-1)
da lista de parâmetros, ficaremos com os parâmetros regulares em $1
em 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
segurava “-a”, mas depois do 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.