Por que os espaços entre opções e parâmetros podem ser omitidos?

16

Por exemplo:

xargs -n 1

é o mesmo que

xargs -n1

Mas se você olhar para a página do manual , a opção será listada como -n max-args, o que significa que o espaço deve ser preservado. Não há nada sobre a forma abreviada -n max-args .

Isso também acontece com muitos outros utilitários Linux.

Como isso é chamado no Linux? Todos os utilitários suportam o formulário abreviado (mas nunca o documentam na página de manual)?

J.Joe
fonte
1
12.1.2.a é parte da história; Eu juro que já há uma boa pergunta aqui sobre isso, mas ainda não a encontrei.
2
@drewbenn a outra pergunta que você está pensando de poderia ter sido meu: unix.stackexchange.com/q/188046/41515

Respostas:

12

Ao escrever a linha de comando que analisa parte do seu código, você especifica quais opções recebem argumentos e quais não. Por exemplo, em um script de shell que aceita uma -hopção (para obter ajuda, por exemplo) e uma -aopção que deve receber um argumento, você deve

opt_h=0     # default value
opt_a=""

while getopts 'a:h' opt; do
    case $opt in
        h)  opt_h=1 ;;
        a)  opt_a="$OPTARG" ;;
    esac
done

echo "h: $opt_h"
echo "a: $opt_a"

O a:htrecho diz "Estou esperando analisar duas opções -ae -h, e -adeve aceitar um argumento" (é o :seguinte aque diz ao analisador que -aaceita um argumento).

Portanto, nunca há ambiguidade em onde uma opção termina, onde seu valor começa e onde outra começa depois disso.

Executando:

$ bash test.sh -h -a hello
h: 1
a: hello

$ bash test.sh -h -ahello
h: 1
a: hello

$ bash test.sh -hahello
h: 1
a: hello

É por isso que na maioria das vezes você não deve escrever seu próprio analisador de linha de comando para analisar as opções.

Há apenas um caso neste exemplo que é complicado. A análise geralmente para na primeira não opção, portanto, quando você tem coisas na linha de comando que se parecem com opções:

$ bash test.sh -a hello -world
test.sh: illegal option -- w
test.sh: illegal option -- o
test.sh: illegal option -- r
test.sh: illegal option -- l
test.sh: illegal option -- d
h: 0
a: hello

O seguinte resolve que:

$ bash test.sh -a hello -- -world
h: 0
a: hello

Ele --sinaliza as opções de final de linha de comando e o -worldbit é deixado para o programa fazer o que quiser (está em uma das variáveis ​​posicionais).

A propósito, é assim que você remove um arquivo com um traço no início de seu nome de arquivo rm.

EDIT :

Os utilitários escritos em C chamam getopt()(declarados em unistd.h) que funcionam praticamente da mesma maneira. Na verdade, por tudo que sabemos, a bashfunção getoptspode ser implementado usando uma chamada para a função de biblioteca C getopt(). Perl, Python e outras linguagens têm bibliotecas de análise de linha de comando semelhantes e é mais provável que elas realizem sua análise de maneiras semelhantes.

Algumas dessas rotinas de biblioteca getopte getoptsimilares também lidam com opções "longas". Geralmente, são precedidos por double-dash ( --), e as opções longas que recebem argumentos geralmente o fazem após um sinal de igual, por exemplo, a --block-size=SIZEopção de [algumas implementações do] duutilitário (que também permite -B SIZEespecificar a mesma coisa).

Os manuais de razão são muitas vezes escritos para mostrar um espaço entre as opções curtas e seus argumentos provavelmente para facilitar a leitura.

EDIT : Ferramentas realmente antigas, como os utilitários dde tar, têm opções sem traços na frente deles. Isso é puramente por razões históricas e para manter a compatibilidade com o software que depende deles para funcionar exatamente dessa maneira. O tarutilitário ganhou a capacidade de escolher opções com traços nos últimos tempos. O manual do BSD tarchama as opções de estilo antigo para "sinalizadores agrupados".

Kusalananda
fonte
Esse recurso pode parecer fácil de implementar nos scripts do bash. Mas acho que a maioria dos utilitários são escritos em C (depois compilados em binários) e não no bash. Por que esses utilitários implementam esse recurso?
26416 J.Joe
@ J.Joe Porque eles chamam getopt()(declarado em unistd.h), o que faz a mesma coisa.
Kusalananda
2
Sim, você está certo. Referência . Isso também resolve outro mistério que as opções podem ser combinadas -a -b=== -ab
J.Joe
1
Argumentos opcionais para sinalizadores criariam uma ambiguidade, portanto eles não podem ser combinados (se -ativer argumento opcional, -abnão será o mesmo -a -b). O GNU getopt não interrompe o processamento de sinalizadores ao encontrar um não sinalizador: em vez disso (por padrão), em vez disso, reorganiza os sinalizadores na frente do argv.
Ilkkachu
@ilkkachu Obrigado por esse esclarecimento. Posso atualizar minha resposta mais tarde.
Kusalananda
4

xargsé um dos utilitários POSIX. Conforme comentado por @drewbenn, o POSIX documenta o comportamento de análise de opções para a maioria de seus utilitários getopt, com algumas permissões para outras implementações, dizendo na 12.1 Sintaxe de argumentos do utilitário :

Esta seção descreve a sintaxe do argumento dos utilitários padrão e apresenta a terminologia usada em todo o POSIX.1-2008 para descrever os argumentos processados ​​pelos utilitários.

No POSIX.1-2008, uma notação especial é usada para descrever a sintaxe dos argumentos de um utilitário. Salvo indicação em contrário , todas as descrições de utilitários usam esta notação, que é ilustrada por este exemplo (consulte XCU Simple Commands ):

e concluindo com

É recomendável que todos os utilitários e aplicativos futuros usem essas diretrizes para melhorar a portabilidade do usuário. O fato de alguns utilitários históricos não poderem ser alterados (para evitar a quebra de aplicativos existentes) não deve impedir esse objetivo futuro.

No POSIX (lembre-se de que ele cobre apenas os utilitários mais usados), há exceções que passam operandos que seriam opções em outros utilitários como parâmetros posicionais ou parâmetros com sintaxe especial :

O POSIX permite valores opcionais de opção:

Os argumentos da opção são mostrados separados de suas opções por <blank>caracteres, exceto quando o argumento da opção é colocado na notação '['e ']'para indicar que é opcional.

Imediatamente, não me lembro quais utilitários POSIX usam o recurso. As ncurses tice infocmputilitários usam o recurso para níveis da opção -v(detalhado / depurar).

O ponto específico sobre o qual você perguntou está detalhado no restante desse parágrafo, em várias linhas.

Antes do POSIX, algumas implementações de psopções aceitas sem um hífen à esquerda. A descrição do POSIX não menciona isso na descrição do utilitário ou na lógica da sintaxe:

Além do POSIX, existem implementações de opções longas (como GNU getopt_long ou X Toolkit ), usando várias maneiras de separar ou associar o valor de uma opção à opção. Por exemplo, a pontuação pode ser usada:

--option=value
--option value

Dependendo da implementação, um traço duplo pode / não pode ser usado para distinguir opções longas de curta (getopt): lynx e X Toolkit usam um único traço; O GNU getopt_longusa um traço duplo, por exemplo. Além disso, a +pode ser usado para indicar que uma opção é negada.

A descrição do POSIX não parece mencionar nada disso, mas é provável que você os encontre.

Thomas Dickey
fonte
É -option=valuesuposto ser --option=value(o formato de longa opção, dois traços no início, em vez de um)?
J.Joe
Alguns utilitários legados usam opções longas de traço único (-opção), mas são em grande parte preteridos para novos scripts e programas. Use um traço para opções curtas, conforme manipulado por getopt. Quase todos os novos scripts e programas usam opções longas de traço duplo. Muitos também oferecem suporte a opções curtas de traço único para as mais usadas. Opções longas tornam o código de script muito mais auto-documentado, necessitando de menos comentários.
DocSalvager