
Estou tentando extrair tudosinopses de comandodas páginas de manual em /usr/share/man/man1
uso:
#!/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 fornecealgunsmedida de sucesso - obtenho resultados completos para comandos deaparaz. Mas também estou recebendo muitos errosstderrusando ambos for i in ./*.gz; do man "$i"
efor i in *.gz; do man "./$i"
conforme eu envio para o arquivo( 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
Sobre o que são esses <standard input>
erros (algo escapou?) E por que man
acaba não encontrando alguns arquivos? Como eu poderia tornar isso mais robusto/eficiente?
1. Parece que os erros emstderrsão os mesmos, independentemente da implementação/solução que uso para os mesmos dados. É impressionante.
Responder1
Você não pode simplesmente correrParece que vocêpodeexecute man foo.gz
man foo.1.gz
, mas usando o -l
parece mais limpo. 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.
Então, seu script deve 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
O awk
comando que dou funciona melhor do que a sua abordagem (teste-o, man ajc
por exemplo) e agora também funciona em sinopses multilinhas. A maioria dos erros que você vê são irrelevantes, outros se devem à maneira como você lida com os nomes dos arquivos. Deixe-me saber se este funciona melhor.
Responder2
Em relação aos erros que você encontra, todos eles são abordados aqui:
man man
MANWIDTH
- Se$MANWIDTH
estiver definido, seu valor será usado como o comprimento da linha para a qual as páginas de manual devem ser formatadas. Se não estiver definido, as páginas de manual serão formatadas com um comprimento de linha apropriado ao terminal atual (usando um ioctl(2) se disponível, o valor de$COLUMNS
, ou voltando para 80 caracteres se nenhum estiver disponível). As páginas Cat só serão salvas quando a formatação padrão puder ser usada, ou seja, quando o comprimento da linha do terminal estiver entre 66 e 80 caracteres.
MAN_KEEP_FORMATTING
- Normalmente, quando a saída não está sendo direcionada para um terminal (como um arquivo ou pipe), os caracteres de formatação são descartados para facilitar a leitura do resultado sem ferramentas especiais. No entanto, se$MAN_KEEP_FORMATTING
for definido com qualquer valor não vazio, esses caracteres de formatação serão mantidos. Isso pode ser útil para wrappers man que podem interpretar caracteres de formatação.
MAN_KEEP_STDERR
- Normalmente, quando a saída está sendo direcionada para um terminal (geralmente para um pager), qualquer saída de erro do comando usado para produzir versões formatadas de páginas de manual é descartada para evitar interferir na exibição do pager. Programas como essegroff
geralmente produzem mensagens de erro relativamente pequenas sobre problemas tipográficos, como mau alinhamento, que são desagradáveis e geralmente confusas quando exibidas junto com a página de manual. No entanto, alguns usuários desejam vê-los de qualquer maneira, portanto, se$MAN_KEEP_STDERR
for definido como qualquer valor não vazio, a saída de erro será exibida normalmente.
E agora sobre como você pode fazer a outra coisa:
Eu acho que isso faz o que você quer:
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
Ele especifica que sed
seja o PAGER
e então gera apenas a linha seguinteNOMEe aqueles que seguemSINOPSEaté encontrar qualquer outra linha começando com algo diferente de a <space>
. Ele imprimenadase a primeira linha não começar com <space>
a seguinteNOMEnão corresponde a start [Ss][Yy][Nn]
. Em todos os casos, ele para de ler o arquivo na segunda linha que encontra apósNOMEisso não começa com <space>
. Ele limpa <spaces>
todas \b
as barras iniciais e de entrada da saída.
Eu executei o for
loop agora há pouco e ele percorreu toda a minha man
biblioteca em apenas um minuto.
man
ajusta sua saída com base no fato de ela gravar em um terminal ou em um pipe/arquivo. Então, se você pedir para fazer isso, ele renunciará completamente ao PAGER. Isso foi inesperado. Mas eu enganei e usei w
a função rite do sed para escrever para >&2 e redirecionei isso para que não fosse mais sábio.
Uma observação - porém - pode ser que @terdon seja o melhor caminho a seguir. Embora você possa adaptar isso mais facilmente porque obtém um sed
arquivo por arquivo, e a formatação é um pouco melhor porque não tenta ajustar a largura do terminal, aparentemente man
não grava essas barras invertidas em um arquivo |pipe
.