Como grep um título em uma manpage contendo caracteres de controle

1

Eu tenho uma página de manual e quero encontrar algo em uma seção específica. Grep está tendo dificuldades, e descobri que o assunto é que os títulos têm caracteres de controle, por exemplo,

SEE ALSO

é realmente:

S^HSE^HEE^HE A^HAL^HLS^HSO^HO$

(obrigado, cat -e , aprendi isso hoje também)

Joguei com muitas variantes do grep & sed, usando classes de personagens e outras técnicas e simplesmente não foi capaz de pregá-lo.

Alguma sugestão sobre a melhor forma de retornar, diga "tudo na seção VEJA TAMBÉM"? Isso deve ser genérico o suficiente para ser útil aos outros, mas específico o suficiente para uma resposta detalhada. :)

Note que, na verdade, não quero ajuda com man , porque, nesse caso, a saída está sendo gerada por outro comando, como aws help , que passa para menos.

    
por halr9000 18.11.2015 / 23:05

3 respostas

3

A idéia de como obter uma versão simples das páginas man pode ser encontrada em man man :

man foo | col -b

Com base nisso, você pode obter apenas uma seção, por exemplo, com pcregrep :

man man | col -b | pcregrep -Mo '^SEE ALSO(.|\n)*?^[^ ]'

Você pode ajustar um pouco e colocar em funcionamento g rep em qualquer s ection de qualquer man ual facilmente:

gsman () { man $1 | col -b | pcregrep -iMo "^$2(.|\n)*?(?=\n[A-Z])" ; }

e o uso seria

gsman grep options | grep invert
    
por 19.11.2015 / 00:06
2

Um dumper hexadecimal ( hexdump , xxd ) e ascii(7) podem ser úteis aqui:

man ls | hexdump -C
...

Que mostra:

000045f0  35 29 2e 0a 0a 53 08 53  45 08 45 45 08 45 20 41  |5)...S.SE.EE.E A|
00004600  08 41 4c 08 4c 53 08 53  4f 08 4f 0a 20 20 20 20  |.AL.LS.SO.O.    |

Então, é o código hexadecimal 8, ou um monte de bs (que também é o que o ^H mostrado por cat significa). Quanto a como remover o bs , há várias maneiras:

% man ls | perl -ple 'tr/\x08//d' | grep SEE
SSEEEE AALLSSOO

Bem, isso não é bom, você também precisa se livrar do personagem que está sendo espaçado:

% man ls | perl -ple 's/.\x08//g' | perl -00 -nle 'print if m/SEE ALSO/'
SEE ALSO
     chflags(1), chmod(1), sort(1), xterm(1), compat(5), termcap(5),
     symlink(7), sticky(8)
    
por 18.11.2015 / 23:44
1
section="SEE ALSO"
regex=$(sed 's/./&.*/g' <<<"$section")       # S.*E.*E.* .*A.*L.*S.*O.*
# then
some help command | sed -n '/^'"$regex"'/,/^[^[:blank:]]/ p' | sed '$d'
  • A expressão regular permite qualquer número de caracteres entre cada letra do nome da seção especificada.
  • o primeiro comando sed apenas mostra as linhas entre a regex da seção dada e a próxima seção (suponho que todas as linhas da seção possuam espaços em branco iniciais)
  • o segundo comando sed remove o título da seção final.

Como uma função bash:

man_section() {
    local section=$1
    local regex=$(sed 's/./&.*/g' <<<"$section")
    sed -n '/^'"$regex"'/,/^[^[:blank:]]/ p' | sed '$d'
}

some help command | man_section "SEE ALSO"
    
por 18.11.2015 / 23:43