
Você deseja que seus scripts de shell do Linux lidem com opções e argumentos de linha de comando com mais facilidade? O Bash getoptsintegrado 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 $1pela primeira variável, $2pela 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 lspodem 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 lscomando possui mais de 50 opções, principalmente relacionadas à formatação de sua saída. A -Xopção (classificar por extensão) classifica a saída em ordem alfabética por extensão de arquivo . A -Uopçã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 -wopçã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 getoptslida 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 getoptcom comportamentos diferentes, enquanto o getopsbuilt-in segue as diretrizes POSIX.
digite getopts
digite getopt

Como getoptnã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 é getoptsnã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 , -cgetoptspermite combiná-las como -abc, -bca, ou -bace 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 -aou -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, $2ou $3.
Copie este texto em um editor e salve-o como um arquivo chamado “variables.sh”. Precisaremos torná-lo executável com o chmodcomando . 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 $3foram 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 getoptsem whileloop. 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, getoptspassa para a próxima opção. Quando não há mais opções, getoptsretorna falsee o whileloop é encerrado.
A OPTIONvariá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
feitoEsta é a linha que define o loop while.
enquanto getopts 'abc' OPÇÃO; Faz
O getoptscomando é 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, -dseria inválido. Isso seria capturado pela ?)cláusula porque getoptsretorna 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 $0scripts 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
feitoQuando 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 getoptsque 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, getoptesperaremos 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 getoptprocessa uma opção com um argumento, o argumento é colocado na OPTARGvariá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 whileloop 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 $1em diante são preenchidas com os sinalizadores de opção e seus argumentos. No último exemplo, $4manteria 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 OPTINDe o shiftcomando.
O shiftcomando 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 $2se torna $1, $3se torna $2, e assim por diante.
Se você fornecer shiftum número, essa quantidade de parâmetros será retirada da lista.
OPTINDconta 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 $1diante.
É 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
feitoVamos 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, $1seguramos “-a”, mas depois que o comando shift $1manté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 getoptsvocê 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.
