Como combinar uma forma particular de sequência opcional de uma sinopse manual, incluindo variações?

2

Em este Q & A, há uma referência às sinopses das manpages baseadas "vagamente" no < a href="http://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_Form"> Formulário Backus – Naur estendido da notação metassyntax. É interessante e serve como pano de fundo. Dito isto, usando terminologia relacionada, um dos tipos mais comuns de elemento que você encontrará em uma sinopse de comando de um manual é a seqüência opcional ; feita de uma lista de definições entre um símbolo da opção de início e um símbolo da opção final . Em muitas palavras, algo que costumamos associar com os gostos de [ option ] que, por exemplo, podem ser um único traço ou um formulário de traço duplo mais longo seguido de um ou mais caracteres, como em ps --help .

Então, eu gostaria de combinar um padrão de seqüência opcional comum que costumamos ver nos manuais que, na verdade:

  • Começa com [ e termina com ]
  • Contém uma sequência opcional na forma de -option ou --option
  • Não é necessariamente centralizado dentro de um colchete, por exemplo, [-a] , [ -ab] , [-abc ] all match
  • Permite uma lista contendo uma opção e seu elemento / especificador opcional, por exemplo, [-a foo -b bar -c=biz end]
  • Permite que outros colchetes apareçam dentro dos colchetes externos, ou seja, [--a [-b[-c]] -d foo] (corresponderia a toda a entrada aqui)

... mas não permite:

  • Três traços --- em qualquer circunstância
  • Para ser mais claro, itens como [option] (sem traço) e [] , [-] , [--] ou [foo-bar=a] sozinhos não devem corresponder.

Os dados não contêm muitos casos incomuns, como os exemplos apresentados acima (eu não saberia como negociar com colchetes inigualáveis, mas isso está além do escopo disso). Tentar abordar os requisitos com grep , como eu fiz, talvez não seja a melhor ideia em retrospectiva, mas tentei:

grep -E '\[{1,}([[:space:]]{0,}[[:punct:]]{0,}[[:alnum:]]{0,}){0,}(-{1,2}[[:alpha:]]{1,}){1,}([[:alnum:]]{0,}[[:punct:]]{0,}[[:space:]]{0,}){0,}\]{1,}'

Ele está combinando alguns padrões 1 , nos moldes do que eu quero, mas tem falhas, é difícil de gerenciar e reutilizar. Usar conjuntos de arbitragem (3) de parênteses para agrupar itens a fim de gerenciar repetições correspondentes para criar "blocos" também não ajuda nesse aspecto (mas ajuda na depuração). Jogar com classes de personagens para atender a entrada parece bastante imprevisível.

Então, como você faz isso usando uma expressão melhor e / ou uma ferramenta / abordagem diferente? Como você gerencia expressões regulares tão longas se você usá-las - nesse caso, você deve usar um comando várias vezes para filtrar o conteúdo? Preciso manipular o conteúdo de forma diferente para me ajudar com isso?

1. A saída da iteração pelos arquivos manpages oferece uma boa oportunidade para testes. Com o grep aqui eu usei: for i in /usr/share/man/man1/*.gz; do basename "${i//.1.gz}"; my_grep_command_above <<< "$(man -l "$i")"; done usando toda a saída do manpages. Caso contrário, man man ou man as fornece uma boa variação de sequências opcionais para teste.

    
por jus cogens prime 19.06.2014 / 21:07

1 resposta

2

Você poderia fazer (com GNU grep ):

grep -Po '\[\s*--?(?!-)((?>[^][]+)|\[(?1)*\])+\]'

Qual é o texto da sua pergunta:

[-a]
[ -ab]
[-abc ]
[-a foo -b bar -c=biz end]
[--a [-b[-c]] -d foo]

A idéia é usar o PCRE e seus operadores de correspondência recursiva, conforme descrito em pcrepattern(3) para correspondência aninhada [...] .

    
por 19.06.2014 / 22:40