Ao desenvolver o aplicativo, comecei a me perguntar: como devo projetar argumentos de linha de comando?
Muitos programas estão usando fórmula como esta -argument value
ou /argument value
. A solução que me veio à mente foi argument:value
. Eu pensei que era bom porque, sem espaços em branco, não há como os valores e argumentos serem confusos. Também é fácil dividir uma string em duas no primeiro :
caractere esquerdo .
Minhas perguntas são:
- A
-argument value
fórmula popular é melhor queargument:value
(mais legível, mais fácil de escrever, sem erros, mais fácil de entender por desenvolvedores especializados)? - Existem algumas regras conhecidas que devo seguir ao criar argumentos de linha de comando (exceto se funcionar, tudo bem)?
Pediu mais alguns detalhes que irei fornecer. No entanto, acho que eles não devem afetar as respostas. A questão é sobre bons hábitos em geral. Eu acho que eles são todos iguais para todos os tipos de aplicações.
Estamos trabalhando em um aplicativo que será usado em locais públicos (totens de toque, tabelas). Os aplicativos são gravados usando o Qt Quick 5 (C ++, QML, JS). Os dispositivos terão o Windows 8.1 / 10 instalado. Forneceremos interface front-end para gerenciar os dispositivos. No entanto, alguns administradores avançados podem querer configurar o aplicativo por conta própria. Não é muito importante do lado dos negócios, mas, como concordo com o que Kilian Foth disse, não quero que meu aplicativo seja um problema para o usuário. Não encontrando na Internet o que quero, perguntei aqui.
Para usuários mais avançados do Stack Exchange: Eu queria que essa pergunta fosse geral. Talvez ele se qualifique para o wiki da comunidade (não sei se a pergunta existente pode ser convertida com respostas). Como eu quero que essa pergunta seja independente do sistema operacional e da linguagem de programação, as respostas que aparecem aqui podem ser uma lição valiosa para outros desenvolvedores.
fonte
ls -ltr
para combinar as opções-l
,-t
e-r
. Os programas no estilo GNU também geralmente permitem opções baseadas em palavras com um hífen duplo como em--reverse
vez de-r
. Há outras convenções populares como-h
para mostrar a ajuda,--
para sinalizar o final de opções, especificando-
como um nome de arquivo para permitir a leitura de stdin, etc.-argument value
não-argument:value
são comuns. Comuns são-a value
,-avalue
e--argument=value
.getopt(s)
) onde você puder.Respostas:
Em sistemas POSIX (por exemplo, Linux, MacOSX), pelo menos para programas possivelmente iniciados em um terminal shell (por exemplo, a maioria deles), eu recomendaria o uso das convenções de codificação GNU (que também listam nomes de argumentos comuns) e consulte as diretrizes dos utilitários do POSIX , mesmo para software proprietário:
sempre manuseie
--version
e--help
(até os/bin/true
aceite !!). Eu amaldiçoo os autores de software que não entendem--help
, eu os odeio (porqueprog --help
é o primeiro comando que estou tentando em um novo programa)! Muitas vezes,--help
pode ser abreviado como-h
Faça com que a
--help
mensagem liste todas as opções (a menos que você tenha muitas delas ... nesse caso, liste as mais comuns e se refira explicitamente a algumaman
página ou URL) e valores padrão de opções, e talvez importantes (e específicos do programa ) variáveis ambientais. Mostre essas listas de opções no erro de argumento da opção.aceitar
-a
argumento curto (única letra) e ter algum equivalente--long-argument
, então-a2
--long-argument=2
,--long-argument 2
; é claro que você pode ter (para opções raramente usadas) algum--only-long-argument
nome; para argumentos modais sem opções extras-cf
geralmente é tratado como-c -f
etc., portanto, sua-argument:value
proposta é estranha e eu não recomendo fazer isso.usar GLIBC getopt_long ou melhor (por exemplo argp_parse , em OCaml é
Arg
módulo , ...)geralmente use
-
para entrada ou saída padrão (se você não puder fazer isso, manipule/dev/stdin
e/dev/stdout
até nos poucos sistemas operacionais que não os possuem)imitar o comportamento de programas similares, reutilizando a maioria de suas convenções de opções; em particular
-n
para corrida a seco (à lamake
),-h
ajuda,-v
verbosidade, etc ...use
--
como separador entre opções e arquivo ou outros argumentosse o seu programa usa
isatty
para testar se stdin é um terminal (e se comportar "interativamente" nesse caso), forneça uma opção para forçar o modo não interativo, da mesma forma se o seu programa tiver uma interface GUI (e for testadagetenv("DISPLAY")
na área de trabalho do X11), mas também puder ser usado em lote ou linha de comando.Alguns programas (por exemplo
gcc
) aceitam listas de argumentos indiretos, o que@somefile.txt
significa ler argumentos do programa emsomefile.txt
; isso pode ser útil quando seu programa pode aceitar muitos argumentos (mais que os do seu kernelARG_MAX
)BTW, você pode até adicionar alguns recursos de preenchimento automático para o seu programa e shells habituais (como
bash
ouzsh
)Alguns comandos antigos do Unix (por exemplo
dd
, ou mesmosed
) têm argumentos de comando estranhos para compatibilidade histórica. Eu recomendaria não seguir seus maus hábitos (a menos que você esteja fazendo uma variante melhor deles).Se o seu software é uma série de programas de linha de comando relacionados, ter inspiração de git (que você certamente usar como uma ferramenta de desenvolvimento), que aceita
git help
egit --help
e têm muitosgit
subcommand
egit
subcommand
--help
Em casos raros, você também pode usar
argv[0]
(usando links simbólicos no seu programa), por exemplo,bash
invocado porrbash
ter um comportamento diferente ( shell restrito ). Mas eu geralmente não recomendo fazer isso; pode fazer sentido se o seu programa puder ser usado como intérprete de script usando shebang, isto é,#!
na primeira linha interpretada por execve (2) . Se você fizer esses truques, certifique-se de documentá-los, inclusive nas--help
mensagens.Lembre-se de que, no POSIX, o shell apresenta argumentos esquisitos ( antes de executar seu programa!), Portanto, evite exigir caracteres (como
*
ou$
ou~
) em opções que precisariam ser escapadas do shell.Em alguns casos, você pode incorporar um intérprete como GNU guile ou Lua em seu software (evite inventar sua própria linguagem de script Turing-completa se você não for especialista em linguagens de programação). Isso tem profundas conseqüências no design do seu software (por isso, deve-se pensar no início!). Você deve passar facilmente algum script ou expressão para esse intérprete. Se você adotar essa abordagem interessante, projete seu software e suas primitivas interpretadas com cuidado; você pode ter um usuário estranho codificando grandes scripts para sua coisa.
Em outros casos, convém permitir que usuários avançados carreguem seus plug - ins no software (usando técnicas de carregamento dinâmico à la
dlopen
&dlsym
). Novamente, essa é uma decisão de design muito importante (portanto, defina e documente a interface do plug-in com cuidado) e você precisará definir uma convenção para passar as opções do programa para esses plug-ins.Se o seu software for algo complexo, aceite alguns arquivos de configuração (além ou substitua os argumentos do programa) e provavelmente tenha alguma maneira de testar (ou apenas analisar) esses arquivos de configuração sem executar todo o código. Por exemplo, um agente de transferência de correio (como Exim ou Postfix) é bastante complexo e é útil poder executá-lo "pela metade" (por exemplo, observar como ele está lidando com um determinado endereço de email sem realmente enviar um email).
Observe que
/option
é uma coisa do Windows ou VMS. Seria insano em sistemas POSIX (porque a hierarquia de arquivos usa/
como um separador de diretório e porque o shell faz o globbing). Toda a minha resposta é principalmente para Linux (e POSIX).PS Se possível, torne seu programa um software livre , você obterá melhorias de alguns usuários e desenvolvedores (e adicionar uma nova opção de programa geralmente é uma das coisas mais fáceis de se adicionar a um software livre existente). Além disso, sua pergunta depende muito do público - alvo : um jogo para adolescentes ou um navegador para a avó provavelmente não precisa do mesmo tipo e quantidade de opções que um compilador, ou um inspetor de rede para administradores de sistemas de datacenter ou um software CAD para microprocessador arquitetos ou para projetistas de pontes. Um engenheiro familiarizado com programação e script provavelmente gosta muito mais de ter muitas opções ajustáveis do que a sua avó e provavelmente pode querer executar seu aplicativo sem o X11 (talvez em um
crontab
emprego).fonte
git
é um exemplo melhor. Eu não vou recomendar mesmo olhando paracvs
em 2016.dd -h
.--help
como regra, mas geralmente não reconhecem o-h
que é irritante. Normalmente, digite -h quando esqueço uma opção para um programa, é irritante ter que redigitar o comando com a opção mais longa--help
. Afinal, digitei -h porque esqueci alguma coisa. Por que o usuário deve se lembrar de quais programas requerem '--help' e quais programas exigem '-h' para exibir a tela de ajuda? Basta incluir uma opção para -h e --help.O fato de uma convenção de formato de dados ser popular é sua vantagem.
Você pode ver facilmente que usar = ou: ou mesmo '' como separador são diferenças triviais que podem ser convertidas entre si por computador com pouco esforço. O que seria um grande esforço para um ser humano se lembrar "Agora, veja, esse programa pouco usado delimita as coisas com
:
ou com=
? Hmmm ..."Em outras palavras, pelo amor de Deus, não se desvie de convenções extremamente arraigadas sem uma razão convincente. As pessoas se lembrarão do seu programa como "aquele com a sintaxe estranha e irritante do cmdline" em vez de "aquele que salvou meu ensaio da faculdade".
fonte
dd
usa umakey=value
sintaxe. O motivo dessa decisão de design é que essa ferramenta (apelido: d ata d estroyer) pode causar muitos danos quando usada incorretamente. Ao forçar o usuário a abandonar seu hábito habitual, força o usuário a pensar mais de perto sobre o que está fazendo.dd
? Eu acredito que ele simplesmente foi codificado em uma época (década de 1970?) Quando o ARG_MAX do kernel era pequeno, os shells não tinham auto-conclusões e--long-arguments
não existiam. Desde então, melhordd
permaneceu compatível com versões anterioresdd
originou-se de outro sistema operacional (que não o UNIX) - uma linguagem de script (JCL) no OS / 360 da IBM - em que as convenções eram diferentes, antes de serem portadas mais ou menos inalteradas para o UNIX - em parte porque os que provavelmente o usavam o conheciam pelo sistema anterior.Em termos leigos
Quando em Roma, faça como os romanos.
-p value
ou--parameter value
. O Linux possui ferramentas para analisar esses parâmetros e sinalizadores de maneira fácil.Eu costumo fazer algo assim:
Se o seu aplicativo CLI for destinado ao Windows, use
/flag
e/flag:value
convenções.Alguns aplicativos como o Oracle não usam nenhum deles. Utilitários Oracle usam
PARAMETER=VALUE
.Uma coisa que eu gosto de fazer é, além de aceitar parâmetros na linha de comando, fornecer a opção de usar um parfile , que é um arquivo de par de valores-chave para evitar longas cadeias de parâmetros. Para isso, você deve fornecer um
--parfile mifile.par
parâmetro adicional . Obviamente, se--parfile
for usado, todos os outros parâmetros serão descartados em favor do que está dentro do parfile.Uma sugestão adicional é permitir o uso de algumas variáveis de ambiente personalizadas , por exemplo, definir variáveis de ambiente
MYAPP_WRKSPACE=/tmp
tornaria desnecessário sempre definir--wrkspace /tmp
.TAB
e, em seguida, o shell o concluirá para eles.fonte
gcc
) lidam@mifile.par
com suas--parfile mifile.par
sugestões.fooCmd -opt1 -opt2 $(cat more_options.opts)
. Portanto, eu esperaria que uma opção "parâmetro do arquivo de configuração", se fornecida, funcionasse basicamente da mesma maneira.Uma coisa que ainda não surgiu:
Tente projetar seu software a partir dos argumentos da linha de comando para cima. Significado:
Antes de projetar a funcionalidade, projete a interface do usuário.
Isso permitirá que você faça uma pesquisa detalhada de casos extremos e casos comuns desde o início. É claro que você ainda abstrairá o exterior e o interior, mas isso dará um resultado muito melhor do que apenas escrever todo o código e, em seguida, bater uma CLI nele.
Além disso, consulte o docopt ( http://docopt.org/ ).
O docopt é uma grande ajuda para isso em muitas linguagens, especialmente para python, onde você tem limitadores severos de analisadores de argumentos adversos ao usuário, como o argparse, ainda sendo considerado "OK". Em vez de ter parsers e subparsers e dicts condicionais, você apenas define a ajuda da sintaxe e faz o resto.
fonte
argparse
não ser um programador, interface de usuário ou amigável.Alguns comentários valiosos já foram fornecidos (@Florian, Basile), mas deixe-me acrescentar ... OP diz:
Mas também observa:
Você deve considerar seu público-alvo - administradores avançados . Em que plataforma eles normalmente trabalham - Win / Unix / Mac? E em qual plataforma você trabalha? Siga as convenções da CLI já estabelecidas para essa plataforma. Seus administradores "avançados" desejam / precisam de uma ferramenta baseada em GUI?
Você deseja que a interface seja consistente internamente e com outras ferramentas administrativas. Não quero parar e pensar que é
cmd -p <arg>
oucmd -p:<arg>
ou nãocmd /p <arg>
. Preciso de aspas porque existe um espaço? Possocmd -p <val1> <val2>
oucmd -p <val1> -p <val2>
para vários destinos? Eles são pedidos específicos? Sobrecarregável? Será quecmd -p2 <arg> -p1 <arg>
trabalhar também? Será quels -l -r -t dir1 dir2
==ls -trl dir1 dir2
?Para minhas ferramentas administrativas do Unix, sempre lembrei das orientações fornecidas pelo Shelldorado de Heiner, além das outras referências mencionadas.
Tão importante quanto projetar a CLI é garantir que seu aplicativo seja projetado para funcionar com argumentos de linha de comando iguais aos da GUI - ou seja: nenhuma lógica de negócios na GUI ou use o comando comum chamado da GUI e da CLI.
A maioria das ferramentas administrativas baseadas em UNIX são projetadas primeiro como ferramentas de linhas de comando e a GUI fornecida simplesmente facilita o "preenchimento" das opções da linha de comando. Essa abordagem permite a automação, o uso de arquivos de resposta etc. e o gerenciamento manual (menos trabalho para mim!)
Como conjunto de ferramentas clássico usado com essa abordagem é Tcl / Tk . Não estou sugerindo que você troque de ferramenta; basta considerar a abordagem de design ao escrever um aplicativo administrativo baseado em GUI no aplicativo como uma ferramenta de linha de comando; em seguida, coloque a GUI na parte superior por conveniência. Em algum momento, você provavelmente descobrirá que a GUI é problemática (e propensa a erros) se precisar fazer várias configurações e inserir novamente geralmente as mesmas opções repetidas vezes e procurar uma abordagem automatizada.
Lembre-se de que seu administrador provavelmente precisará digitar os valores corretos nas caixas corretas de qualquer maneira; portanto, quanto esforço você está aliviando com a GUI?
fonte