EmessePerguntas e respostas, há uma referência às sinopses das páginas de manual sendo baseadas "vagamente" noFormulário Backus – Naur Estendidoda notação metassintaxe. É interessante e serve de pano de fundo. Dito isto, usando terminologia relacionada, um dos tipos de elemento mais comuns que você encontrará em uma sinopse de comando de um manual é osequência opcional; feito de umlista de definiçõesfechado entre umsímbolo de opção de inícioe umsímbolo de opção final. Em outras palavras, algo que frequentemente associamos a algo como [ option ]
, por exemplo, poderia ser um único travessão ou um 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 sequência opcional comum que vemos frequentemente nos manuais que de fato:
- Começa
[
e termina com]
- Contém uma sequência opcional noformade
-option
ou--option
- Não está necessariamente centralizado dentro de um colchete
[-a]
, ou seja,[ -ab]
,[-abc ]
todas correspondem - Permite uma lista contendo uma opção e seu elemento/especificador opcional, ou seja
[-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)
... masnãopermitir:
- Três travessões
---
em qualquer circunstância - Para ser mais claro, coisas como
[option]
(sem travessão) e[]
,[-]
,[--]
ou[foo-bar=a]
sozinhas não devem corresponder.
Os dados não contêm muitos casos incomuns como os exemplos apresentados acima(eu não saberia comonegóciocom colchetes incomparáveis, mas isso está além do escopo deste artigo). Tentar atender aos requisitos grep
como fiz talvez não tenha sido 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 corresponde a alguns padrões 1 , na linha do que eu quero, mas tem deficiências, é difícil de gerenciar e reutilizar. Usar conjuntos arbitrários (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). Brincar com classes de personagens para atender às informações 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ê as usa - nesse caso, você deveria usar um comando várias vezes para filtrar o conteúdo? Preciso manipular o conteúdo de forma diferente antes para me ajudar com isso?
1. Osaídade iterar pelos arquivos de páginas de manual oferece uma boa oportunidade para testes. Com 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 das páginas de manual. Caso contrário, man man
or man as
fornece uma boa variação de sequências opcionais para teste.
Responder1
Você poderia fazer (com GNU grep
):
grep -Po '\[\s*--?(?!-)((?>[^][]+)|\[(?1)*\])+\]'
Que no texto da sua pergunta dá:
[-a]
[ -ab]
[-abc ]
[-a foo -b bar -c=biz end]
[--a [-b[-c]] -d foo]
A ideia é usar PCRE e seus operadores de correspondência recursiva conforme descrito em pcrepattern(3)
para correspondência aninhada [...]
.