/usr/share/man/man1 のマニュアルページからすべてのコマンド概要を正しく抽出するにはどうすればよいですか?

/usr/share/man/man1 のマニュアルページからすべてのコマンド概要を正しく抽出するにはどうすればよいですか?

すべてを抽出しようとしているコマンドの概要使用中のマニュアルページから/usr/share/man/man1:

#!/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

...これはいくつかの成功の尺度 - コマンドの完全な出力が得られる1つのしかし、私はまた多くのエラーが発生します標準エラー出力両方for i in ./*.gz; do man "$i"を使用してfor i in *.gz; do man "./$i"ファイルに出力したときsynopses > file1

<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

<standard input>これらのエラーは何に関するものでしょうか(何かがエスケープされましたか?) また、man一部のファイルが見つからないのはなぜですか? これをより堅牢かつ効率的にするにはどうすればよいでしょうか?


1. エラーは標準エラー出力同じデータに対してどのような実装/ソリューションを使用しても同じです。驚くべきことです。

答え1

ただ走るだけではだめだman foo.gzあなたみたいですねできる実行しますman foo.1.gzが、 を使用する方-lがきれいです。 出典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.

したがって、スクリプトは次のようになります。

#!/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

私が示すコマンドawkは、あなたのアプローチよりもうまく機能し (たとえば、テストしてくださいman ajc)、複数行の概要でも機能するようになりました。表示されるエラーのほとんどは無関係ですが、他のエラーはファイル名の処理方法によるものです。この方法の方がうまくいくかどうか教えてください。

答え2

発生したエラーについては、すべてここで対処します。

man man

MANWIDTH-$MANWIDTHが設定されている場合、その値はマニュアル ページをフォーマットする行の長さとして使用されます。設定されていない場合、マニュアル ページは現在の端末に適した行の長さでフォーマットされます (使用可能な場合は ioctl(2) を使用し、 の値を使用し$COLUMNS、どちらも使用できない場合は 80 文字に戻ります)。cat ページは、デフォルトのフォーマットが使用できる場合、つまり端末の行の長さが 66 から 80 文字の間である場合にのみ保存されます。

MAN_KEEP_FORMATTING- 通常、出力が端末 (ファイルやパイプなど) に送信されていない場合、特別なツールを使わずに結果を読みやすくするために、書式設定文字は破棄されます。ただし、が$MAN_KEEP_FORMATTING空でない値に設定されている場合、これらの書式設定文字は保持されます。これは、書式設定文字を解釈できる man のラッパーに役立つ場合があります。

MAN_KEEP_STDERR- 通常、出力が端末(通常はページャ)に向けられている場合、マニュアル ページのフォーマットされたバージョンを作成するために使用されるコマンドからのエラー出力は、ページャの表示を妨げないように破棄されます。 などのプログラムは、groff配置の不備などの印刷上の問題に関する比較的軽微なエラー メッセージを生成することが多く、マニュアル ページと一緒に表示されると見苦しく、一般的に混乱を招きます。ただし、一部のユーザーはエラー メッセージを見たいと考えているため、 が$MAN_KEEP_STDERR空でない値に設定されている場合、エラー出力は通常どおり表示されます。

さて、もう一つのことについてはどうするか。

これがあなたの望みを実現すると思います:

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

を指定し、次の行のみを出力しますsedPAGER名前そしてそれに続く概要以外の文字で始まる行に出会うまで<space>何もない最初の行が<space>thatで始まっていない場合は名前begin と一致しません[Ss][Yy][Nn]。いずれの場合も、次の2行目でファイルの読み取りを完全に中止します。名前で始まっていない<space>。出力から先頭のアックスラッシュ<spaces>とすべてのアックスラッシュをクリアします。\b

for先ほどループで実行したところ、manわずか 1 分でライブラリ全体がループされました。

man出力をターミナルに書き込むか、パイプ/ファイルに書き込むかに基づいて調整します。そのため、そのように指示すると、PAGER が完全に無視されます。これは予想外でした。しかし、私はそれを騙して、sed のwrite 関数を使用して >&2 に書き出し、それをリダイレクトしたので、何もわかりませんでした。

ただし、@terdon の方法のほうが良いかもしれません。sedファイルごとに を取得できるので、簡単にカスタマイズできます。また、端末の幅に合わせようとしないのでフォーマットが少し良くなりますが、どうやら にmanは \backslashes が書き込まれないようです|pipe

関連情報