
Я пытаюсь извлечь всесводки командиз страниц руководства по /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
...которая обеспечиваетнекоторыймера успеха - я получаю полный вывод для команд отакз. Но я также получаю много ошибок наstderrиспользуя оба for i in ./*.gz; do man "$i"
иfor i in *.gz; do man "./$i"
как я вывожу в файл( 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
Что это <standard input>
за ошибки (что-то ускользнуло?) и почему man
в итоге не находят некоторые файлы? Как сделать это более надежным/эффективным?
1. Кажется, ошибки наstderrодинаковы, какую бы реализацию/решение я ни использовал для одних и тех же данных. Это поразительно.
решение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
Он указывает, что sed
будет PAGER
и затем выводит только строку, следующую заИМЯи те, кто следуютСИНОПСИСпока не встретит любую другую строку, начинающуюся с чего-либо, кроме a <space>
. Он печатаетничегоесли первая строка не начинается с <space>
этого, следуетИМЯне соответствует begin [Ss][Yy][Nn]
. В каждом случае он прекращает чтение файла на второй строке, которую он встречает послеИМЯ, который не начинается с <space>
. Он очищает начальные <spaces>
и все \b
косые черты из вывода.
Я только что запустил его в for
цикле, и он прошел по всей моей man
библиотеке всего за минуту.
man
корректирует свой вывод в зависимости от того, пишет ли он в терминал или в канал/файл. Так что если вы скажете ему сделать это, он вообще откажется от PAGER. Это было неожиданно. Но я обманул его и использовал w
функцию rite sed, чтобы записать в >&2 и перенаправить ее, так что он не стал умнее.
Примечание - хотя - возможно, это будет лучшим способом @terdon. Хотя вы можете настроить это проще, потому что вы получаете sed
по файлу, и форматирование немного лучше, потому что оно не пытается соответствовать ширине терминала, по-видимому, man
не записывает эти \обратные косые черты в |pipe
.