
Estoy tratando de extraer todosinopsis de comandosdesde páginas de manual al /usr/share/man/man1
usar:
#!/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é man
no 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 correrSe parece a tipoderejecutar man foo.gz
man foo.1.gz
pero usar -l
parece 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 awk
comando que doy funciona mejor que su enfoque (pruébelo, man ajc
por 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$MANWIDTH
está 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$COLUMNS
o 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_FORMATTING
se 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 comogroff
suelen 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_STDERR
se 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 sed
sea el PAGER
y 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 \b
de la salida.
Lo ejecuté en el for
bucle hace un momento y recorrió toda mi man
biblioteca en solo un minuto.
man
ajusta 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é w
la 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 sed
archivo por archivo y el formato es un poco mejor porque no intenta ajustarse al ancho de un terminal, aparentemente man
no escribe esas \barras invertidas en un archivo |pipe
.