¿Cómo se extraen correctamente todas las sinopsis de comandos de las páginas de manual en /usr/share/man/man1?

¿Cómo se extraen correctamente todas las sinopsis de comandos de las páginas de manual en /usr/share/man/man1?

Estoy tratando de extraer todosinopsis de comandosdesde páginas de manual al /usr/share/man/man1usar:

#!/usr/bin/env bash
## synopses - extract all synopses in /usr/share/man/man1

cd /usr/share/man/man1
for i in *.gz; do
    echo "$i:" | sed -E "s/.1.gz|.gz//g"
    man "./$i" | sed -n '/^SYNOPSIS/,/^[A-Z][A-Z][A-Z]/p' | sed -e '1d; $d' | tr -s [:space:]
done

...que proporcionaalgunomedida de éxito: obtengo resultados completos para los comandos deaaz. Pero también recibo muchos erroresstderrusando ambos for i in ./*.gz; do man "$i"yfor i in *.gz; do man "./$i"mientras salgo al archivo( synopses > file) 1 :

<standard input>:27: expected `;' after scale-indicator (got `o')
<standard input>:29: expected `;' after scale-indicator (got `o')
<standard input>:283: name expected (got `\{'): treated as missing
<standard input>:674: warning: macro `as',' not defined (possibly missing space after `as')
<standard input>:174: name expected (got `\{'): treated as missing
<standard input>:161: warning [p 1, 5.5i]: can't break line
<standard input>:594: warning [p 5, 3.8i, div `an-div', 0.0i]: can't break line
<standard input>:569: warning [p 6, 0.0i]: can't break line
<standard input>:147: warning [p 1, 1.8i]: can't break line
<standard input>:205: warning [p 2, 0.2i]: can't break line
<standard input>:525: warning [p 5, 4.5i]: can't break line
<standard input>:157: warning [p 1, 4.8i]: can't break line
<standard input>:351: warning [p 3, 1.8i, div `an-div', 0.0i]: can't break line
<standard input>:147: a space character is not allowed in an escape name
man: can't open man1/zshmisc.1: No such file or directory
man: -:423: warning: failed .so request
man: can't open man1/zshexpn.1: No such file or directory
man: -:423: warning: failed .so request
man: can't open man1/zshparam.1: No such file or directory
man: -:423: warning: failed .so request
man: can't open man1/zshoptions.1: No such file or directory
man: -:423: warning: failed .so request
man: can't open man1/zshbuiltins.1: No such file or directory
man: -:423: warning: failed .so request
man: can't open man1/zshzle.1: No such file or directory
man: -:423: warning: failed .so request
man: can't open man1/zshcompwid.1: No such file or directory
man: -:423: warning: failed .so request
man: can't open man1/zshcompsys.1: No such file or directory
man: -:423: warning: failed .so request
man: can't open man1/zshcompctl.1: No such file or directory
man: -:423: warning: failed .so request
man: can't open man1/zshmodules.1: No such file or directory
man: -:423: warning: failed .so request
man: can't open man1/zshcalsys.1: No such file or directory
man: -:423: warning: failed .so request
man: can't open man1/zshtcpsys.1: No such file or directory
man: -:423: warning: failed .so request
man: can't open man1/zshzftpsys.1: No such file or directory
man: -:423: warning: failed .so request
man: can't open man1/zshcontrib.1: No such file or directory
man: -:423: warning: failed .so request
<standard input>:423: can't open `man1/zshmisc.1': No such file or directory
<standard input>:424: can't open `man1/zshexpn.1': No such file or directory
<standard input>:425: can't open `man1/zshparam.1': No such file or directory
<standard input>:426: can't open `man1/zshoptions.1': No such file or directory
<standard input>:427: can't open `man1/zshbuiltins.1': No such file or directory
<standard input>:428: can't open `man1/zshzle.1': No such file or directory
<standard input>:429: can't open `man1/zshcompwid.1': No such file or directory
<standard input>:430: can't open `man1/zshcompsys.1': No such file or directory
<standard input>:431: can't open `man1/zshcompctl.1': No such file or directory
<standard input>:432: can't open `man1/zshmodules.1': No such file or directory
<standard input>:433: can't open `man1/zshcalsys.1': No such file or directory
<standard input>:434: can't open `man1/zshtcpsys.1': No such file or directory
<standard input>:435: can't open `man1/zshzftpsys.1': No such file or directory
<standard input>:436: can't open `man1/zshcontrib.1': No such file or directory

¿A qué se deben esos <standard input>errores (¿algo se escapó?) y por qué manno se encuentran algunos archivos. ¿Cómo podría hacer esto más robusto/eficiente?


1. Parece que los errores enstderrson los mismos independientemente de la implementación/solución que utilice para los mismos datos. Es sorprendente.

Respuesta1

No puedes simplemente correrman foo.gzSe parece a tipoderejecutar man foo.1.gzpero usar -lparece más limpio. De man man:

   -l, --local-file
          Activate `local' mode.  Format and display  local  manual  files
          instead  of  searching  through  the system's manual collection.
          Each manual page argument will be interpreted as an nroff source
          file in the correct format.  No cat file is produced.  If '-' is
          listed as one of the arguments, input will be taken from  stdin.
          When  this  option  is  not used, and man fails to find the page
          required, before displaying the error message,  it  attempts  to
          act as if this option was supplied, using the name as a filename
          and looking for an exact match.

Entonces, tu script debería ser algo como:

#!/usr/bin/env bash
## synopses - extract all synopses in /usr/share/man/man1

## No need to cd into the directory, you can just use globs     
for i in /usr/share/man/man1/ajc*.gz; do
    ## This will print the name of the command.      
    basename "${i//.1.gz}"
    man -l "$i"  | 
       awk '/^SYNOPSIS/{a=1; getline}
            (/^[a-zA-z0-9_]/ && a==1){a=0} 
            (a==1 && /./){print}' | tr -s [:space:]

done

El awkcomando que doy funciona mejor que su enfoque (pruébelo, man ajcpor ejemplo) y ahora también funciona en sinopsis de varias líneas. La mayoría de los errores que ve son irrelevantes, otros se debieron a la forma en que manejaba los nombres de los archivos. Déjame saber si este funciona mejor.

Respuesta2

Con respecto a los errores que encuentre, todos se abordan aquí:

man man

MANWIDTH- Si $MANWIDTHestá configurado, su valor se utiliza como la longitud de línea para la cual se deben formatear las páginas del manual. Si no está configurado, las páginas del manual se formatearán con una longitud de línea apropiada para el terminal actual (usando un ioctl(2) si está disponible, el valor de $COLUMNSo volviendo a 80 caracteres si ninguno está disponible). Las páginas Cat solo se guardarán cuando se pueda utilizar el formato predeterminado, es decir, cuando la longitud de la línea terminal esté entre 66 y 80 caracteres.

MAN_KEEP_FORMATTING- Normalmente, cuando la salida no se dirige a una terminal (como a un archivo o una canalización), los caracteres de formato se descartan para facilitar la lectura del resultado sin herramientas especiales. Sin embargo, si $MAN_KEEP_FORMATTINGse establece en cualquier valor que no esté vacío, estos caracteres de formato se conservan. Esto puede ser útil para contenedores de man que pueden interpretar caracteres de formato.

MAN_KEEP_STDERR- Normalmente, cuando la salida se dirige a una terminal (generalmente a un buscapersonas), cualquier salida de error del comando utilizado para producir versiones formateadas de páginas del manual se descarta para evitar interferir con la visualización del buscapersonas. Programas como groffsuelen producir mensajes de error relativamente menores sobre problemas tipográficos, como una mala alineación, que son antiestéticos y generalmente confusos cuando se muestran junto con la página del manual. Sin embargo, algunos usuarios quieren verlos de todos modos, por lo que, si $MAN_KEEP_STDERRse establece en cualquier valor que no esté vacío, la salida de error se mostrará como de costumbre.

Y ahora sobre cómo podrías hacer la otra cosa:

Creo que esto hace lo que quieres:

for f in /usr/share/man/man1/*gz ; do
    man -P "sed -ne '1,/^[Nn]/d;/^ /{H;b}
    /^[Ss]..[Yy]..[Nn]/{g;:n
    N;/\n\(\n\)[^ ].*/!bn;s//\1/
    s/.\x08//g;s/\(\n\)  */\1/g;
    w /dev/stderr' -ne '};/./q'" -l "$f"
done 2>~/file

Especifica que sedsea el PAGERy luego genera solo la línea que sigueNOMBREy los siguientesSINOPSIShasta que encuentre cualquier otra línea que comience con algo que no sea <space>. se imprimenadasi la primera línea que no comienza con <space>eso sigueNOMBREno coincide con comenzar [Ss][Yy][Nn]. En todos los casos, deja de leer el archivo por completo en la segunda línea que encuentra despuésNOMBREeso no comienza con <space>. Borra las barras iniciales <spaces>y de confirmación \bde la salida.

Lo ejecuté en el forbucle hace un momento y recorrió toda mi manbiblioteca en solo un minuto.

manajusta su salida en función de si escribe en una terminal o en una tubería/archivo. Entonces, si le dice que lo haga, renunciará al PAGER por completo. Eso fue inesperado. Pero lo engañé y usé wla función de rito de sed para escribir en >&2 y lo redirigí para que no se diera cuenta.

Sin embargo, una nota: puede que @terdon sea la mejor manera de hacerlo. Si bien puedes adaptar esto más fácilmente porque obtienes un sedarchivo por archivo y el formato es un poco mejor porque no intenta ajustarse al ancho de un terminal, aparentemente manno escribe esas \barras invertidas en un archivo |pipe.

información relacionada