EnestePreguntas y respuestas: hay una referencia a que las sinopsis de las páginas de manual se basan "libremente" en elForma extendida de Backus-Naurde notación metasintaxis. Es interesante y sirve de fondo. Dicho esto, usando terminología relacionada, uno de los tipos de elementos más comunes que encontrará en la sinopsis de un comando de un manual es elsecuencia opcional; hecho de unlista de definicionesencerrado entre unsímbolo de opción de inicioy unsímbolo de opción final. En pocas palabras, algo que a menudo asociamos con algo como [ option ]
, por ejemplo, podría ser un guión único o un guión doble más largo seguido de uno o más caracteres, como en ps --help
.
Así que me gustaría hacer coincidir un patrón de secuencia opcional común que vemos a menudo en los manuales y que de hecho:
- Comienza con
[
y termina con]
- Contiene una secuencia opcional en elformade
-option
o--option
- No está necesariamente centrado dentro de un corchete
[-a]
, es decir[ -ab]
,[-abc ]
todos coinciden - Permite una lista que contiene una opción y su elemento/especificador opcional, es decir
[-a foo -b bar -c=biz end]
- Permite que aparezcan otros corchetes dentro de los corchetes exteriores, es decir
[--a [-b[-c]] -d foo]
(coincidiría con toda la entrada aquí)
... peronopermitir:
- Tres guiones
---
bajo cualquier circunstancia. - Para ser más claro, elementos como
[option]
(sin guión) y[]
,[-]
o[--]
solo[foo-bar=a]
no deberían coincidir.
Los datos no contienen demasiados casos inusuales como los ejemplos presentados anteriormente (no sabría cómotratocon corchetes inigualables, pero eso está más allá del alcance de esto). Tratar de abordar los requisitos grep
como lo hice tal vez no fue la mejor idea en retrospectiva, pero lo intenté:
grep -E '\[{1,}([[:space:]]{0,}[[:punct:]]{0,}[[:alnum:]]{0,}){0,}(-{1,2}[[:alpha:]]{1,}){1,}([[:alnum:]]{0,}[[:punct:]]{0,}[[:space:]]{0,}){0,}\]{1,}'
Coincide con algunos patrones 1 , según lo que quiero, pero tiene deficiencias, es difícil de administrar y reutilizar. El uso de conjuntos arbitrarios (3) de paréntesis para agrupar elementos con el fin de gestionar repeticiones coincidentes para crear "bloques" tampoco ayuda en ese sentido (pero ayuda con la depuración). Jugar con clases de personajes para atender las entradas parece bastante impredecible.
Entonces, ¿cómo se hace esto usando una mejor expresión y/o una herramienta/enfoque diferente? ¿Cómo gestiona expresiones regulares tan largas si las usa? En este caso, ¿debería utilizar un comando muchas veces para filtrar el contenido? ¿Necesito manipular el contenido de manera diferente de antemano para ayudarme con eso?
1. ElproducciónLa iteración a través de los archivos de las páginas de manual ofrece una buena oportunidad para realizar pruebas. Con grep aquí usé: for i in /usr/share/man/man1/*.gz; do basename "${i//.1.gz}"; my_grep_command_above <<< "$(man -l "$i")"; done
usando la totalidad de la salida de las páginas de manual. De lo contrario man man
, man as
proporciona una buena variación de secuencias opcionales para realizar pruebas.
Respuesta1
Podrías hacer (con GNU grep
):
grep -Po '\[\s*--?(?!-)((?>[^][]+)|\[(?1)*\])+\]'
Que en el texto de su pregunta da:
[-a]
[ -ab]
[-abc ]
[-a foo -b bar -c=biz end]
[--a [-b[-c]] -d foo]
La idea es utilizar PCRE y sus operadores de coincidencia recursivos como se describe en pcrepattern(3)
Coincidencia anidada [...]
.