Pourquoi les shellins embeddeds n'ont-ils pas de bonnes pages man?

Tous les builtins shell partagent la même page de manuel:

BUILTIN(1) BSD General Commands Manual BUILTIN(1) NAME builtin, ! 

etc.

Ensuite, il y a un petit text décrivant ce que sont les shellins embeddeds, puis une list qui ressemble à ceci:

  Command External csh(1) sh(1) ! No No Yes % No Yes No 

Mais si nous faisons l' man grep nous obtenons des sections telles que

  • Bogues
  • Histoire
  • Voir également
  • Normes
  • La description

etc.

Ne pas shell builtins ont leur propre histoire, description et arguments comme -A ou -r ? Pourquoi n'est-ce pas fourni dans les pages de manuel et comment pourrais-je apprendre à les utiliser correctement et efficacement?

Parce que les builtins font partie de la coquille. Tous les bugs ou l'histoire qu'ils ont sont des bugs et l'histoire de la coquille elle-même. Ce ne sont pas des commands indépendantes et elles n'existent pas en dehors du shell dans lequel elles sont embeddedes.

L'équivalent, pour bash au less, est la command help . Par exemple:

 $ help while while: while COMMANDS; do COMMANDS; done Execute commands as long as a test succeeds. Expand and execute COMMANDS as long as the final command in the `while' COMMANDS has an exit status of zero. Exit Status: Returns the status of the last command executed. 

Tous les builtins bash ont des pages d' help . Même help lui-même:

 $ help help help: help [-dms] [pattern ...] Display information about builtin commands. Displays brief summaries of builtin commands. If PATTERN is specified, gives detailed help on all commands matching PATTERN, otherwise the list of help topics is printed. Options: -d output short description for each topic -m display usage in pseudo-manpage format -s output only a short usage synopsis for each topic matching PATTERN Arguments: PATTERN Pattern specifiying a help topic Exit Status: Returns success unless PATTERN is not found or an invalid option is given. 

Inspiré par le script sed @ mikeserv, voici une petite fonction qui va imprimer la section pertinente d'une page man en utilisant Perl. Ajoutez cette ligne au file d'initialisation de votre shell ( ~/.bashrc pour bash):

 manperl(){ man "$1" | perl -00ne "print if /^\s*$2\b/"; } 

Ensuite, vous l'exécutez en lui donnant une page man et le nom d'une section:

 $ manperl bash while while list-1; do list-2; done until list-1; do list-2; done The while command continuously executes the list list-2 as long as the last command in the list list-1 returns an exit status of zero. The until command is identical to the while command, except that the test is negated; list-2 is exe‐ cuted as long as the last command in list-1 returns a non-zero exit status. The exit status of the while and until commands is the exit status of the last command executed in list-2, or zero if none was executed. $ manperl grep SYNOPSIS SYNOPSIS grep [OPTIONS] PATTERN [FILE...] grep [OPTIONS] [-e PATTERN | -f FILE] [FILE...] $ manperl rsync "-r" -r, --recursive This tells rsync to copy directories recursively. See also --dirs (-d). 

Même s'il est vrai que certaines interprétations de shell peuvent apparaître dans un manuel complet, en particulier pour les constructions spécifiques à bash que vous utilisez uniquement sur un système GNU (les gens de GNU, en règle générale, ne croient pas man et préfèrent leurs propres pages d' info ) – la très grande majorité des utilitaires POSIX – embeddeds au shell ou non – sont très bien représentés dans le Guide du programmeur POSIX.

Voici un extrait du fond de mon man sh (qui est probablement de 20 pages ou plus …)

entrer la description de l'image ici

Tous ceux-là sont là, et d'autres non mentionnés, tels que set , read , break … eh bien, je n'ai pas besoin de tous les nommer. Mais notez le (1P) en bas à droite – il désigne la série manuelle POSIX catégorie 1 – ce sont les pages de man je parle.

Il se peut que vous ayez juste besoin d'installer un package? Cela semble prometteur pour un système Debian. Alors que l' help est utile, si vous pouvez le find, vous devriez certainement get cette série POSIX Programmer's Guide . Cela peut être extrêmement utile. Et ce sont les pages constituantes qui sont très détaillées.

Cela mis à part, les builtins shell sont presque toujours listés dans une section spécifique du manuel du shell spécifique. zsh , par exemple, a une page de man séparée pour cela – (je pense qu'il totalise 8 ou 9 pages zsh individuelles – y compris zshall qui est énorme).

Vous pouvez juste grep man bien sûr:

 man bash 2>/dev/null | grep '^[[:blank:]]*read [^`]*[-[]' -A14 read [-ers] [-a aname] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [name ...] One line is read from the standard input, or from the file descriptor fd supplied as an argument to the -u option, and the first word is assigned to the first name, the sec‐ ond word to the second name, and so on, with leftover words and their intervening separa‐ tors assigned to the last name. If there are fewer words read from the input stream than names, the remaining names are assigned empty values. The characters in IFS are used to split the line into words using the same rules the shell uses for expansion 

… ce qui est assez proche de ce que j'avais l'habitude de faire lors de la search sur une page shell man . Mais l' help est assez bonne dans bash dans la plupart des cas.

J'ai travaillé sur un script sed pour gérer ce genre de choses récemment. C'est comme ça que j'ai attrapé la section de l'image ci-dessus. Il est encore plus long que je l'aime, mais il s'améliore – et peut être très pratique. Dans son itération actuelle, il extrait de manière assez fiable une section de text sensible au context qui correspond à un en-tête de section ou de sous-section en fonction de [a] pattern [s] donné sur la command line. Il colore sa sortie et imprime sur stdout.

Il fonctionne en évaluant les niveaux de retrait. Les lignes d'input non vides sont généralement ignorées, mais lorsqu'elles rencontrent une ligne vide, elles commencent à faire attention. Il recueille des lignes à partir de là jusqu'à ce qu'il ait vérifié que la séquence actuelle définit définitivement plus loin que sa première ligne avant qu'une autre ligne vierge se produise ou bien il laisse tomber le fil et attend le prochain blanc. Si le test réussit, il essaie de faire correspondre la ligne principale à ses arguments de command line.

Cela signifie qu'un model de correspondance va correspondre:

 heading match ... ... ... text... 

..et..

 match text 

..mais non..

 heading match match notmatch 

..ou..

  text match match text more text 

Si une correspondance peut être obtenue, elle commence à imprimer. Il découpera les blancs de la ligne correspondante de toutes les lignes qu'il imprime – donc, peu importe le niveau de retrait, il trouve que la ligne sur elle l'imprime comme s'il était en haut. Il continuera à imprimer jusqu'à ce qu'il rencontre une autre ligne à un niveau inférieur ou égal à la ligne correspondante. Ainsi, des sections entières sont saisies uniquement avec une correspondance de titre, y compris toutes les sous-sections, tous les paragraphes qu'elles peuvent contenir.

Donc, fondamentalement, si vous lui requestz de faire correspondre un motif, il ne le fera que contre un sujet de quelque sorte et colorera et imprimera tout le text qu'il trouve dans la section dirigée par son appariement. Rien n'est sauvegardé comme il le fait sauf l'indentation de votre première ligne – et donc il peut être très rapide et gérer \n Ewline input séparée de pratiquement n'importe quelle taille.

Il m'a fallu un certain time pour comprendre comment recurse en sous-titres comme ce qui suit:

 Section Heading Subsection Heading 

Mais je l'ai sortingé par la suite.

J'ai cependant dû retravailler le tout pour des raisons de simplicité. Alors qu'avant j'avais plusieurs petites loops faisant la même chose de manière légèrement différente pour adapter leur context, en faisant varier leurs moyens de récursion, j'ai réussi à dédupliquer la majorité du code. Maintenant, il y a deux loops – l'une imprime et l'autre vérifie le retrait. Les deux dépendent du même test: la boucle d'printing commence lorsque le test est réussi et que la boucle de retrait prend le relais lorsqu'elle échoue ou commence sur une ligne vide.

L'set du process est très rapide car la plupart du time, il suffit de /./d toute ligne non vide et passer au suivant – même les résultats de zshall l'écran instantanément. Cela n'a pas changé.

Quoi qu'il en soit, il est très utile jusqu'à présent, cependant. Par exemple, la read ci-dessus peut être faite comme read :

 mansed bash read 

… et il obtient tout le bloc. Il peut prendre n'importe quels motifs ou n'importe quoi, ou plusieurs arguments, bien que le premier soit toujours la page de manuel dans laquelle il devrait searchr. Voici une image de certains de ses résultats après moi:

 mansed bash read printf 

entrer la description de l'image ici

… les deux blocs sont returnnés entiers. Je l'utilise souvent comme:

 mansed ksh '[Cc]ommand.*' 

… pour lequel c'est très utile. En outre, get SYNOPS[ES] rend très pratique:

entrer la description de l'image ici

Le voici si vous voulez lui donner un tourbillon – je ne vous blâmerai pas si vous ne le faites pas.

 mansed() { MAN_KEEP_FORMATTING=1 man "$1" 2>/dev/null | ( shift b='[:blank:]' s='[:space:]' bs=$(printf \\b) esc=$(printf '\033\[') n='\ ' match=$(printf "\([${b}]*%s[${b}].*\)*" "$@") sed -n "1p /\n/!{ /./{ \$p;d };x; /.*\n/!g;s///;x :indent /.*\n\n/{s///;x };n;\$p; /^\([^${s}].*\)*$/{s/./ &/;h; b indent };x; s/.*\n[^-[]*\n.*//; /./!x;t s/[${s}]*$//; s/\n[${b}]\{2,\}/${n} /;G;h }; #test /^\([${b}]*\)\([^${b}].*\n\)\1\([${b}]\)/!b indent s//\1\2.\3/ :print /^[${s}]*\n\./{ s///;s/\n\./${n}/ /${bs}/{s/\n/ & /g; s/\(\(.\)${bs}\2\)\{1,\}/${esc}38;5;35m&${esc}0m/g s/\(_${bs}[^_]\)\{1,\}/${esc}38;5;75m&${esc}0m/g s/.${bs}//g;s/ \n /${n}/g s/\(\(${esc}\)0m\2[^m]*m[_ ]\{,2\}\)\{2\}/_/g };p;g;N;/\n$/!D s//./; t print }; #match s/\n.*/ /; s/.${bs}//g s/^\(${match}\).*/${n}\1/ /../{ s/^\([${s}]*\)\(.*\)/\1${n}/ x; s//${n}\1${n}. \2/; P };D ");} 

En bref, le stream de travail est:

  • toute ligne qui n'est pas vide et qui ne contient pas de caractère \n ewline est supprimée de la sortie.
    • \n Les caractères ewline ne se produisent jamais dans l'espace des motifs d'input. Ils ne peuvent être obtenus qu'à la suite d'un assembly.
  • :print et :indent sont des loops fermées mutuellement dépendantes et sont la seule façon d'get un \n ewline.
    • :print le cycle de boucle d' :print commence si les caractères principaux d'une ligne sont une série de blancs suivie d'un caractère \n ewline.
    • :indent le cycle de :indent commence sur des lignes vides – ou sur :print lignes de cycle d' :print qui échouent #test – mais :indent supprime toutes les séquences vierges + \n ewline de sa sortie.
    • une fois :print commence, les lignes d'input continuent d'être tirées, les bandes sont distantes de la première ligne de leur cycle, elles se transforment en chevauchements de colors et impriment les résultats jusqu'à ce que #test échoue.
    • before :indent commence en :indent abord l'ancien espace pour une continuation éventuelle d'indentation (comme une sous-section) , puis continue à tirer l'input tant que #test échoue et que toute ligne qui suit le premier continue à correspondre à [- . Lorsqu'une ligne après la première ne correspond pas à ce model, elle est supprimée – et par la suite, toutes les lignes suivantes sont ajoutées jusqu'à la ligne suivante.
  • #match et #test #match les deux loops fermées.
    • #test passe lorsque la première série de blancs est plus courte que la série suivie par le dernier \n ewline dans une séquence de lignes.
    • #match ajoute les \n lignes nécessaires pour lancer un cycle d' :print sur :indent les séquences de sortie de l'indent qui conduisent à une correspondance avec n'importe quel argument de command line. Les séquences qui ne sont pas rendues vides – et la ligne vide résultante est renvoyée à :indent .

Chaque shell a son propre set de builtins. Bien qu'il existe des points communs, ils ont chacun leurs propres particularités qui doivent être documentées.

Sur les systèmes comme Linux et FreeBSD (et OSX, qui hérite de FreeBSD) où chaque shell est fourni comme un package séparé, il n'y a pas de page de manuel pour les builtins; à la place, chaque construit est documenté dans la page de man du shell. Lisez donc la page de bash man pour la documentation de bash's kill , lisez la page dash man pour la documentation de kill dash, etc. Il y a aussi une page man pour l'utilitaire kill standalone.

Voir Puis-je get des pages de manuel individuelles pour les commands bash embeddedes? pour une fonction man qui affiche la documentation interne de bash au lieu de la page man si l'argument est le nom d'un builtin.

Il y a des variantes unix qui fournissent des pages de manuel pour les builtins shell – en fait, la plupart des variantes commerciales font. C'est faisable parce que le système est livré avec une seule coquille, ou un set de coquilles connues. La page de manuel discute les différences entre les coquilles. Par exemple, la page de manuel fg(1) sur Solaris 10 comporte des sections pour sh , ksh et csh . La page de manuel fg(1) sur AIX 7.1 fait reference à "shell Korn" et "shell POSIX" mais les traite set (ils supportent exactement les mêmes fonctionnalités pour fg ). La page de manuel fg(1) sur Tru64 5.0 traite de la construction de ksh et renvoie les users de csh à la page de manuel de csh(1) . SCO apparemment vient avec une seule coquille. Vous pouvez installer d'autres shells en tant que modules complémentaires sur ces systèmes d'exploitation; si vous utilisez un shell personnalisé, vous devez vous callbacker que les pages man pour les builtins ne seront pas pertinentes lors de l'utilisation d'un shell non par défaut.