Ordem dos argumentos da linha de comando

6

Alguém me disse uma vez que havia um padrão quando se trata de analisar opções na linha de comando. Algo como:

./script.sh [options/flags] [command or file]

Eu entendo que ao analisar um shell script isso torna a vida mais fácil, já que você pode shift através dos flags e qualquer coisa deixada pode ser acessada por $@ or $* , mas existe um padrão escrito real?

A maioria dos programas que eu observei segue este padrão, mas há algumas exceções, por exemplo, ls onde ls -l /path , ls /path -l e ls /path -l /path2 são todos aceitáveis.

    
por DarkHeart 10.01.2017 / 07:53

2 respostas

7

As definições base do POSIX tem uma seção sobre " Convenções de utilidade " que se aplica ao POSIX utilitários de base.

O utilitário getopts padrão e o getopt() ("função C") segue as diretrizes (mais abaixo na página vinculada acima) ao analisar o comando linha em um script de shell ou programa C. Especificamente, para getopts (como um exemplo):

When the end of options is encountered, the getopts utility shall exit with a return value greater than zero; the shell variable OPTIND shall be set to the index of the first operand, or the value "$#" +1 if there are no operands; the name variable shall be set to the character. Any of the following shall identify the end of options: the first -- argument that is not an option-argument, finding an argument that is not an option-argument and does not begin with a -, or encountering an error.

O que isso basicamente diz é que as opções devem vir primeiro e, em seguida, operandos (seu "comando ou arquivo").

Fazê-lo de outra maneira renderizaria usando getopts ou getopt() impossível, além de confundir os usuários acostumados com a maneira POSIX de especificar opções e operandos para um comando.

Observe que o padrão mencionado acima se aplica apenas aos utilitários POSIX, mas, como tal, define uma precedência para os utilitários Unix em geral. Os utilitários não-padrão do Unix podem optar por seguir ou quebrar isso, obviamente.

Por exemplo, os coreutils GNU, mesmo que implementem os utilitários padrão, permitem coisas como

$ ls Documents/ -l

se a variável de ambiente POSIXLY_CORRECT não estiver definida, enquanto a versão BSD dos mesmos utilitários não.

Isto tem como consequência que o seguinte funciona como esperado (se você espera um comportamento POSIX, isto é) em um sistema BSD:

$ touch -- 'test' '-l'

$ ls -l test -l
-rw-r--r--  1 kk  kk  0 Jan 11 16:44 -l  
-rw-r--r--  1 kk  kk  0 Jan 11 16:44 test

Mas em um sistema GNU coreutils, você obtém

$ ls -l test -l
-rw-r--r-- 1 kk kk 0 Jan 11 16:44 test

No entanto:

$ env POSIXLY_CORRECT=1 ls -l test -l

e

$ ls -l -- test -l

fará a coisa "certa" em um sistema GNU também.

    
por 10.01.2017 / 19:33
4

tl; dr

um exemplo

Todas as três bibliotecas de análise de opções com as quais trabalhei em python default permitem argumentos intercalados e fornecem uma ilustração do que é comum:

  1. O agora obsoleto módulo de biblioteca padrão python optparse permite:

    OptionParser.enable_interspersed_args()
    

    Set parsing to not stop on the first non-option, allowing interspersing switches with command arguments. This is the default behavior.

  2. O módulo atual da biblioteca padrão do python argparse permite (e somente permite) argumentos intercalados.

  3. click , a biblioteca que estou favorecendo no momento, permite que argumentos intercalados sejam desativados :

    click.Context(allow_interspersed_args=False)
    

    Mas discute essa possibilidade na seção avançada, sob resolução de problemas argumentos desconhecidos para sub-comandos .

por 10.01.2017 / 08:04