Welcome to TiddlyWiki created by Jeremy Ruston; Copyright © 2004-2007 Jeremy Ruston, Copyright © 2007-2011 UnaMesa Association

    <!--{{{-->
    <link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml' />
    <!--}}}-->

    Background: #fff
    Foreground: #000
    PrimaryPale: #8cf
    PrimaryLight: #18f
    PrimaryMid: #04b
    PrimaryDark: #014
    SecondaryPale: #ffc
    SecondaryLight: #fe8
    SecondaryMid: #db4
    SecondaryDark: #841
    TertiaryPale: #eee
    TertiaryLight: #ccc
    TertiaryMid: #999
    TertiaryDark: #666
    Error: #f88

    /*{{{*/
    body {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}

    a {color:[[ColorPalette::PrimaryMid]];}
    a:hover {background-color:[[ColorPalette::PrimaryMid]]; color:[[ColorPalette::Background]];}
    a img {border:0;}

    h1,h2,h3,h4,h5,h6 {color:[[ColorPalette::SecondaryDark]]; background:transparent;}
    h1 {border-bottom:2px solid [[ColorPalette::TertiaryLight]];}
    h2,h3 {border-bottom:1px solid [[ColorPalette::TertiaryLight]];}

    .button {color:[[ColorPalette::PrimaryDark]]; border:1px solid [[ColorPalette::Background]];}
    .button:hover {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::SecondaryLight]]; border-color:[[ColorPalette::SecondaryMid]];}
    .button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::SecondaryDark]];}

    .header {background:[[ColorPalette::PrimaryMid]];}
    .headerShadow {color:[[ColorPalette::Foreground]];}
    .headerShadow a {font-weight:normal; color:[[ColorPalette::Foreground]];}
    .headerForeground {color:[[ColorPalette::Background]];}
    .headerForeground a {font-weight:normal; color:[[ColorPalette::PrimaryPale]];}

    .tabSelected {color:[[ColorPalette::PrimaryDark]];
    	background:[[ColorPalette::TertiaryPale]];
    	border-left:1px solid [[ColorPalette::TertiaryLight]];
    	border-top:1px solid [[ColorPalette::TertiaryLight]];
    	border-right:1px solid [[ColorPalette::TertiaryLight]];
    }
    .tabUnselected {color:[[ColorPalette::Background]]; background:[[ColorPalette::TertiaryMid]];}
    .tabContents {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::TertiaryPale]]; border:1px solid [[ColorPalette::TertiaryLight]];}
    .tabContents .button {border:0;}

    #sidebar {}
    #sidebarOptions input {border:1px solid [[ColorPalette::PrimaryMid]];}
    #sidebarOptions .sliderPanel {background:[[ColorPalette::PrimaryPale]];}
    #sidebarOptions .sliderPanel a {border:none;color:[[ColorPalette::PrimaryMid]];}
    #sidebarOptions .sliderPanel a:hover {color:[[ColorPalette::Background]]; background:[[ColorPalette::PrimaryMid]];}
    #sidebarOptions .sliderPanel a:active {color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::Background]];}

    .wizard {background:[[ColorPalette::PrimaryPale]]; border:1px solid [[ColorPalette::PrimaryMid]];}
    .wizard h1 {color:[[ColorPalette::PrimaryDark]]; border:none;}
    .wizard h2 {color:[[ColorPalette::Foreground]]; border:none;}
    .wizardStep {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];
    	border:1px solid [[ColorPalette::PrimaryMid]];}
    .wizardStep.wizardStepDone {background:[[ColorPalette::TertiaryLight]];}
    .wizardFooter {background:[[ColorPalette::PrimaryPale]];}
    .wizardFooter .status {background:[[ColorPalette::PrimaryDark]]; color:[[ColorPalette::Background]];}
    .wizard .button {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryLight]]; border: 1px solid;
    	border-color:[[ColorPalette::SecondaryPale]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryPale]];}
    .wizard .button:hover {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Background]];}
    .wizard .button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::Foreground]]; border: 1px solid;
    	border-color:[[ColorPalette::PrimaryDark]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryDark]];}

    .wizard .notChanged {background:transparent;}
    .wizard .changedLocally {background:#80ff80;}
    .wizard .changedServer {background:#8080ff;}
    .wizard .changedBoth {background:#ff8080;}
    .wizard .notFound {background:#ffff80;}
    .wizard .putToServer {background:#ff80ff;}
    .wizard .gotFromServer {background:#80ffff;}

    #messageArea {border:1px solid [[ColorPalette::SecondaryMid]]; background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]];}
    #messageArea .button {color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::SecondaryPale]]; border:none;}

    .popupTiddler {background:[[ColorPalette::TertiaryPale]]; border:2px solid [[ColorPalette::TertiaryMid]];}

    .popup {background:[[ColorPalette::TertiaryPale]]; color:[[ColorPalette::TertiaryDark]]; border-left:1px solid [[ColorPalette::TertiaryMid]]; border-top:1px solid [[ColorPalette::TertiaryMid]]; border-right:2px solid [[ColorPalette::TertiaryDark]]; border-bottom:2px solid [[ColorPalette::TertiaryDark]];}
    .popup hr {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::PrimaryDark]]; border-bottom:1px;}
    .popup li.disabled {color:[[ColorPalette::TertiaryMid]];}
    .popup li a, .popup li a:visited {color:[[ColorPalette::Foreground]]; border: none;}
    .popup li a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; border: none;}
    .popup li a:active {background:[[ColorPalette::SecondaryPale]]; color:[[ColorPalette::Foreground]]; border: none;}
    .popupHighlight {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
    .listBreak div {border-bottom:1px solid [[ColorPalette::TertiaryDark]];}

    .tiddler .defaultCommand {font-weight:bold;}

    .shadow .title {color:[[ColorPalette::TertiaryDark]];}

    .title {color:[[ColorPalette::SecondaryDark]];}
    .subtitle {color:[[ColorPalette::TertiaryDark]];}

    .toolbar {color:[[ColorPalette::PrimaryMid]];}
    .toolbar a {color:[[ColorPalette::TertiaryLight]];}
    .selected .toolbar a {color:[[ColorPalette::TertiaryMid]];}
    .selected .toolbar a:hover {color:[[ColorPalette::Foreground]];}

    .tagging, .tagged {border:1px solid [[ColorPalette::TertiaryPale]]; background-color:[[ColorPalette::TertiaryPale]];}
    .selected .tagging, .selected .tagged {background-color:[[ColorPalette::TertiaryLight]]; border:1px solid [[ColorPalette::TertiaryMid]];}
    .tagging .listTitle, .tagged .listTitle {color:[[ColorPalette::PrimaryDark]];}
    .tagging .button, .tagged .button {border:none;}

    .footer {color:[[ColorPalette::TertiaryLight]];}
    .selected .footer {color:[[ColorPalette::TertiaryMid]];}

    .error, .errorButton {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Error]];}
    .warning {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryPale]];}
    .lowlight {background:[[ColorPalette::TertiaryLight]];}

    .zoomer {background:none; color:[[ColorPalette::TertiaryMid]]; border:3px solid [[ColorPalette::TertiaryMid]];}

    .imageLink, #displayArea .imageLink {background:transparent;}

    .annotation {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; border:2px solid [[ColorPalette::SecondaryMid]];}

    .viewer .listTitle {list-style-type:none; margin-left:-2em;}
    .viewer .button {border:1px solid [[ColorPalette::SecondaryMid]];}
    .viewer blockquote {border-left:3px solid [[ColorPalette::TertiaryDark]];}

    .viewer table, table.twtable {border:2px solid [[ColorPalette::TertiaryDark]];}
    .viewer th, .viewer thead td, .twtable th, .twtable thead td {background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::Background]];}
    .viewer td, .viewer tr, .twtable td, .twtable tr {border:1px solid [[ColorPalette::TertiaryDark]];}

    .viewer pre {border:1px solid [[ColorPalette::SecondaryLight]]; background:[[ColorPalette::SecondaryPale]];}
    .viewer code {color:[[ColorPalette::SecondaryDark]];}
    .viewer hr {border:0; border-top:dashed 1px [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::TertiaryDark]];}

    .highlight, .marked {background:[[ColorPalette::SecondaryLight]];}

    .editor input {border:1px solid [[ColorPalette::PrimaryMid]];}
    .editor textarea {border:1px solid [[ColorPalette::PrimaryMid]]; width:100%;}
    .editorFooter {color:[[ColorPalette::TertiaryMid]];}
    .readOnly {background:[[ColorPalette::TertiaryPale]];}

    #backstageArea {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::TertiaryMid]];}
    #backstageArea a {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
    #backstageArea a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; }
    #backstageArea a.backstageSelTab {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
    #backstageButton a {background:none; color:[[ColorPalette::Background]]; border:none;}
    #backstageButton a:hover {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
    #backstagePanel {background:[[ColorPalette::Background]]; border-color: [[ColorPalette::Background]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]];}
    .backstagePanelFooter .button {border:none; color:[[ColorPalette::Background]];}
    .backstagePanelFooter .button:hover {color:[[ColorPalette::Foreground]];}
    #backstageCloak {background:[[ColorPalette::Foreground]]; opacity:0.6; filter:alpha(opacity=60);}
    /*}}}*/

    /*{{{*/
    * html .tiddler {height:1%;}

    body {font-size:.75em; font-family:arial,helvetica; margin:0; padding:0;}

    h1,h2,h3,h4,h5,h6 {font-weight:bold; text-decoration:none;}
    h1,h2,h3 {padding-bottom:1px; margin-top:1.2em;margin-bottom:0.3em;}
    h4,h5,h6 {margin-top:1em;}
    h1 {font-size:1.35em;}
    h2 {font-size:1.25em;}
    h3 {font-size:1.1em;}
    h4 {font-size:1em;}
    h5 {font-size:.9em;}

    hr {height:1px;}

    a {text-decoration:none;}

    dt {font-weight:bold;}

    ol {list-style-type:decimal;}
    ol ol {list-style-type:lower-alpha;}
    ol ol ol {list-style-type:lower-roman;}
    ol ol ol ol {list-style-type:decimal;}
    ol ol ol ol ol {list-style-type:lower-alpha;}
    ol ol ol ol ol ol {list-style-type:lower-roman;}
    ol ol ol ol ol ol ol {list-style-type:decimal;}

    .txtOptionInput {width:11em;}

    #contentWrapper .chkOptionInput {border:0;}

    .externalLink {text-decoration:underline;}

    .indent {margin-left:3em;}
    .outdent {margin-left:3em; text-indent:-3em;}
    code.escaped {white-space:nowrap;}

    .tiddlyLinkExisting {font-weight:bold;}
    .tiddlyLinkNonExisting {font-style:italic;}

    /* the 'a' is required for IE, otherwise it renders the whole tiddler in bold */
    a.tiddlyLinkNonExisting.shadow {font-weight:bold;}

    #mainMenu .tiddlyLinkExisting,
    	#mainMenu .tiddlyLinkNonExisting,
    	#sidebarTabs .tiddlyLinkNonExisting {font-weight:normal; font-style:normal;}
    #sidebarTabs .tiddlyLinkExisting {font-weight:bold; font-style:normal;}

    .header {position:relative;}
    .header a:hover {background:transparent;}
    .headerShadow {position:relative; padding:4.5em 0 1em 1em; left:-1px; top:-1px;}
    .headerForeground {position:absolute; padding:4.5em 0 1em 1em; left:0; top:0;}

    .siteTitle {font-size:3em;}
    .siteSubtitle {font-size:1.2em;}

    #mainMenu {position:absolute; left:0; width:10em; text-align:right; line-height:1.6em; padding:1.5em 0.5em 0.5em 0.5em; font-size:1.1em;}

    #sidebar {position:absolute; right:3px; width:16em; font-size:.9em;}
    #sidebarOptions {padding-top:0.3em;}
    #sidebarOptions a {margin:0 0.2em; padding:0.2em 0.3em; display:block;}
    #sidebarOptions input {margin:0.4em 0.5em;}
    #sidebarOptions .sliderPanel {margin-left:1em; padding:0.5em; font-size:.85em;}
    #sidebarOptions .sliderPanel a {font-weight:bold; display:inline; padding:0;}
    #sidebarOptions .sliderPanel input {margin:0 0 0.3em 0;}
    #sidebarTabs .tabContents {width:15em; overflow:hidden;}

    .wizard {padding:0.1em 1em 0 2em;}
    .wizard h1 {font-size:2em; font-weight:bold; background:none; padding:0; margin:0.4em 0 0.2em;}
    .wizard h2 {font-size:1.2em; font-weight:bold; background:none; padding:0; margin:0.4em 0 0.2em;}
    .wizardStep {padding:1em 1em 1em 1em;}
    .wizard .button {margin:0.5em 0 0; font-size:1.2em;}
    .wizardFooter {padding:0.8em 0.4em 0.8em 0;}
    .wizardFooter .status {padding:0 0.4em; margin-left:1em;}
    .wizard .button {padding:0.1em 0.2em;}

    #messageArea {position:fixed; top:2em; right:0; margin:0.5em; padding:0.5em; z-index:2000; _position:absolute;}
    .messageToolbar {display:block; text-align:right; padding:0.2em;}
    #messageArea a {text-decoration:underline;}

    .tiddlerPopupButton {padding:0.2em;}
    .popupTiddler {position: absolute; z-index:300; padding:1em; margin:0;}

    .popup {position:absolute; z-index:300; font-size:.9em; padding:0; list-style:none; margin:0;}
    .popup .popupMessage {padding:0.4em;}
    .popup hr {display:block; height:1px; width:auto; padding:0; margin:0.2em 0;}
    .popup li.disabled {padding:0.4em;}
    .popup li a {display:block; padding:0.4em; font-weight:normal; cursor:pointer;}
    .listBreak {font-size:1px; line-height:1px;}
    .listBreak div {margin:2px 0;}

    .tabset {padding:1em 0 0 0.5em;}
    .tab {margin:0 0 0 0.25em; padding:2px;}
    .tabContents {padding:0.5em;}
    .tabContents ul, .tabContents ol {margin:0; padding:0;}
    .txtMainTab .tabContents li {list-style:none;}
    .tabContents li.listLink { margin-left:.75em;}

    #contentWrapper {display:block;}
    #splashScreen {display:none;}

    #displayArea {margin:1em 17em 0 14em;}

    .toolbar {text-align:right; font-size:.9em;}

    .tiddler {padding:1em 1em 0;}

    .missing .viewer,.missing .title {font-style:italic;}

    .title {font-size:1.6em; font-weight:bold;}

    .missing .subtitle {display:none;}
    .subtitle {font-size:1.1em;}

    .tiddler .button {padding:0.2em 0.4em;}

    .tagging {margin:0.5em 0.5em 0.5em 0; float:left; display:none;}
    .isTag .tagging {display:block;}
    .tagged {margin:0.5em; float:right;}
    .tagging, .tagged {font-size:0.9em; padding:0.25em;}
    .tagging ul, .tagged ul {list-style:none; margin:0.25em; padding:0;}
    .tagClear {clear:both;}

    .footer {font-size:.9em;}
    .footer li {display:inline;}

    .annotation {padding:0.5em; margin:0.5em;}

    * html .viewer pre {width:99%; padding:0 0 1em 0;}
    .viewer {line-height:1.4em; padding-top:0.5em;}
    .viewer .button {margin:0 0.25em; padding:0 0.25em;}
    .viewer blockquote {line-height:1.5em; padding-left:0.8em;margin-left:2.5em;}
    .viewer ul, .viewer ol {margin-left:0.5em; padding-left:1.5em;}

    .viewer table, table.twtable {border-collapse:collapse; margin:0.8em 1.0em;}
    .viewer th, .viewer td, .viewer tr,.viewer caption,.twtable th, .twtable td, .twtable tr,.twtable caption {padding:3px;}
    table.listView {font-size:0.85em; margin:0.8em 1.0em;}
    table.listView th, table.listView td, table.listView tr {padding:0 3px 0 3px;}

    .viewer pre {padding:0.5em; margin-left:0.5em; font-size:1.2em; line-height:1.4em; overflow:auto;}
    .viewer code {font-size:1.2em; line-height:1.4em;}

    .editor {font-size:1.1em;}
    .editor input, .editor textarea {display:block; width:100%; font:inherit;}
    .editorFooter {padding:0.25em 0; font-size:.9em;}
    .editorFooter .button {padding-top:0; padding-bottom:0;}

    .fieldsetFix {border:0; padding:0; margin:1px 0px;}

    .zoomer {font-size:1.1em; position:absolute; overflow:hidden;}
    .zoomer div {padding:1em;}

    * html #backstage {width:99%;}
    * html #backstageArea {width:99%;}
    #backstageArea {display:none; position:relative; overflow: hidden; z-index:150; padding:0.3em 0.5em;}
    #backstageToolbar {position:relative;}
    #backstageArea a {font-weight:bold; margin-left:0.5em; padding:0.3em 0.5em;}
    #backstageButton {display:none; position:absolute; z-index:175; top:0; right:0;}
    #backstageButton a {padding:0.1em 0.4em; margin:0.1em;}
    #backstage {position:relative; width:100%; z-index:50;}
    #backstagePanel {display:none; z-index:100; position:absolute; width:90%; margin-left:3em; padding:1em;}
    .backstagePanelFooter {padding-top:0.2em; float:right;}
    .backstagePanelFooter a {padding:0.2em 0.4em;}
    #backstageCloak {display:none; z-index:20; position:absolute; width:100%; height:100px;}

    .whenBackstage {display:none;}
    .backstageVisible .whenBackstage {display:block;}
    /*}}}*/

    /***
    StyleSheet for use when a translation requires any css style changes.
    This StyleSheet can be used directly by languages such as Chinese, Japanese and Korean which need larger font sizes.
    ***/
    /*{{{*/
    body {font-size:0.8em;}
    #sidebarOptions {font-size:1.05em;}
    #sidebarOptions a {font-style:normal;}
    #sidebarOptions .sliderPanel {font-size:0.95em;}
    .subtitle {font-size:0.8em;}
    .viewer table.listView {font-size:0.95em;}
    /*}}}*/

    /*{{{*/
    @media print {
    #mainMenu, #sidebar, #messageArea, .toolbar, #backstageButton, #backstageArea {display: none !important;}
    #displayArea {margin: 1em 1em 0em;}
    noscript {display:none;} /* Fixes a feature in Firefox 1.5.0.2 where print preview displays the noscript content */
    }
    /*}}}*/

    <!--{{{-->
    <div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'>
    <div class='headerShadow'>
    <span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
    <span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
    </div>
    <div class='headerForeground'>
    <span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
    <span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
    </div>
    </div>
    <div id='mainMenu' refresh='content' tiddler='MainMenu'></div>
    <div id='sidebar'>
    <div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>
    <div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>
    </div>
    <div id='displayArea'>
    <div id='messageArea'></div>
    <div id='tiddlerDisplay'></div>
    </div>
    <!--}}}-->

    <!--{{{-->
    <div class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div>
    <div class='title' macro='view title'></div>
    <div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>
    <div class='tagging' macro='tagging'></div>
    <div class='tagged' macro='tags'></div>
    <div class='viewer' macro='view text wikified'></div>
    <div class='tagClear'></div>
    <!--}}}-->

    <!--{{{-->
    <div class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]]'></div>
    <div class='title' macro='view title'></div>
    <div class='editor' macro='edit title'></div>
    <div macro='annotations'></div>
    <div class='editor' macro='edit text'></div>
    <div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser excludeLists'></span></div>
    <!--}}}-->

    To get started with this blank [[TiddlyWiki]], you'll need to modify the following tiddlers:
    * [[SiteTitle]] & [[SiteSubtitle]]: The title and subtitle of the site, as shown above (after saving, they will also appear in the browser title bar)
    * [[MainMenu]]: The menu (usually on the left)
    * [[DefaultTiddlers]]: Contains the names of the tiddlers that you want to appear when the TiddlyWiki is opened
    You'll also need to enter your username for signing your edits: <<option txtUserName>>

    These [[InterfaceOptions]] for customising [[TiddlyWiki]] are saved in your browser

    Your username for signing your edits. Write it as a [[WikiWord]] (eg [[JoeBloggs]])

    <<option txtUserName>>
    <<option chkSaveBackups>> [[SaveBackups]]
    <<option chkAutoSave>> [[AutoSave]]
    <<option chkRegExpSearch>> [[RegExpSearch]]
    <<option chkCaseSensitiveSearch>> [[CaseSensitiveSearch]]
    <<option chkAnimate>> [[EnableAnimations]]

    ----
    Also see [[AdvancedOptions]]

    <<importTiddlers>>

    [[Main]]

    {{{
    EnsureVM: s'assurer que les services sont lancés pour un type de virtualisation

    USAGE
        EnsureVM type

    Les types supportés sont virtualbox et kvm (par défaut)
    }}}

    !Présentation
    nutools est un ensemble d'utilitaires pour faciliter l'utililisation des Unixes, en particulier Linux, mais aussi MacOS X et Cygwin.
    C'est aussi une librairie de scripts shell réutilisables ([[ulib]]) et une librairie de modules python réutilisables (pyulib)

    !Prérequis
    Python >= 2.3 et GNU Awk sont requis pour que toutes les fonctionnalités soient supportées.
    * Sous Linux, lors de l'installation du package, les meilleurs efforts sont fait pour que ces packages soient installés.
    * Sous MacOSX, il faut installer manuellement Fink, DarwinPorts ou Homebrew

    ! Outils
    Chaque outil contient une aide intégrée. Il suffit de lancer l'outil avec l'argument {{{--help}}} pour avoir une aide détaillée.
    * Déploiement d'un répertoire ou d'une archive
    ** [[uinst]]: Déploiement local
    ** [[mkusfx]]: Faire une archive auto-installable avec uinst
    ** [[ruinst]]: Déploiement distant avec uinst
    ** [[runs]]: Lancer un script avec le protocole RUNS
    ** [[rruns]]: Déploiement distant avec runs
    * Librairie réutilisable de scripts shell
    ** [[uinc]]: Dépliage des inclusions dans un fichier
    ** [[ulibsync]]: Faire une copie locale pour un projet de ulib et/ou pyulib
    * Autres outils
    ** [[udir]]: Gestion des paramètres d'un répertoire. Ces paramètres sont entre autres utilisés par uinst et uinc.

    [[GettingStarted]]

    {{{
    SKvm: lancer une machine virtuelle kvm

    USAGE
        SKvm [options] vmName
        SKvm {-l|-A|-g}

    OPTIONS
        -n, --check
            Ne rien faire excepté s'assurer que les modules kvm sont chargés
        -u, --user
            Lancer l'opération avec les droits de l'utilisateur courant. Par défaut,
            ce script tente d'acquérir les droits de root.
        -l, --list
            Lister les machines virtuelles
        -s, --start
            Démarrer la machine virtuelle (par défaut)
            Si le nom de la machine virtuelle n'est pas spécifiée, un menu est
            affiché
        -k, --stop
            Arrêter la machine virtuelle
        -H, --destroy
            Arrêter sauvagement la machine virtuelle
        -r, --restart
            Redémarrer la machine virtuelle
        -S, --managed-save
            Enregistrer l'état de la machine virtuelle
        -A, --stop-all
            Arrêter toutes les machines virtuelles qui tournent actuellement
        -g, --gui
            Afficher le gestionnaire de machines virtuelle
    }}}

    {{{
    SVirtualBox: lancer une machine virtuelle VirtualBox

    USAGE
        SVirtualBox [options] vmName

    OPTIONS
        -n  Ne rien faire excepté s'assurer que les modules VirtualBox sont chargés
        -l  Lister les machines virtuelles
        -s  Démarrer la machine virtuelle (par défaut)
            Si le nom de la machine virtuelle n'est pas spécifiée, un menu est
            affiché
        -b  Démarrer la VM sans interface graphique. Cette option n'est valide
            qu'avec -s
        -k  Arrêter la machine virtuelle (par ACPI)
        -p  Mettre en veille la machine virtuelle (par ACPI)
        -H  Arrêter sauvagement la machine virtuelle
        -R  Redémarrer sauvagement la machine virtuelle
        -S  Enregistrer l'état de la machine virtuelle
        -g  Afficher le gestionnaire de machines virtuelle
    }}}

    Outils divers pour linux/macosx, et librairies pour bash

    nutools

    {{{
    _root: devenir l'utilisateur root, avec 'sudo' si possible, ou 'su' si
    'sudo' n'est pas installé
    }}}

    {{{
    apacheconfig: Gérer la configuration d'un serveur web apache

    USAGE
        apacheconfig -c
        apacheconfig -t -- args...

    OPTIONS
        -c, --create
            Créer un nouveau répertoire de configuration pour un hôte
        -d, --destdir DESTDIR[=apacheconfig]
            Nom du répertoire local de configuration.

        -t, --template [OPT]
            Gérer les fichiers du répertoire local avec templatectl. La valeur de
            cette option est utilisée comme argument court pour l'invocation de
            templatectl, e.g
                apacheconfig -tm args
            est équivalent à
                templatectl -m args
            Les arguments qui restent sont passés tels quels à templatectl
            Les options courantes de templatectl -l, -v, -m, -L sont disponibles
            directement
        --help-template
            Afficher l'aide concernent la gestion des templates.
            Equivalent à -t -- --help
        -h, --host HOST
            Spécifier l'hôte. Equivalent à -v host=HOST
        --sysname SYSNAME
        --sysdist SYSDIST
        -s, --sysver SYSVER
            Spécifier la distribution pour laquelle synchroniser le template. Par
            défaut, choisir les valeurs correspondantes au système courant.
            Les options -7 et -8 sont des aliases respectivement pour -s wheezy et
            -s jessie, parce que les fichiers par défaut ont changé à partir de
            debian jessie.

        -u, --update, --deploy
            Mettre à jour la configuration système à partir du répertoire local.
            Lors du déploiement de la configuration, les valeurs des variables
            dynamiques sont remplacées dans les fichiers destination.
            Les arguments qui restent sont passés tels quels à apache_autoconf
        -r, --certsdir CERTSDIR
            Spécifier le cas échéant le répertoire contenant les certificats à
            déployer. Cet argument est requis si le répertoire certsconf/ existe.

        --localhosts
            Créer dans le fichier /etc/hosts tous les noms d'hôte ayant un suffixe
            .local mentionnés dans les fichiers de site. Cette option est utile pour
            le développement et les tests.
        -C, --one-conf CONF
            Ne déployer que le fichier de configuration spécifié. Cette option est
            utilisée avec --deploy et est utile pour le développement et les tests.
        -M, --one-module MODULE
            Ne déployer que le fichier de module spécifié. Cette option est utilisée
            avec --deploy et est utile pour le développement et les tests.
        -S, --one-site SITE
            Ne déployer que le fichier de site spécifié. Cette option est utilisée
            avec --deploy ou --localhosts et est utile pour le développement et les
            tests.
    }}}

    {{{
    authftp: Se connecter sur un site FTP authentifié
    Ce script nécessite ncftp. Il est conçu pour faciliter l'accès à des sites FTP
    s'il est requis d'y accéder par un proxy FTP pour les connexion authentifiées.

    USAGE
        authftp [options] host login password [path]

    OPTIONS
        -p, --proxy
        -n, --noproxy
            Forcer l'utilisation, resp. ne pas utiliser, le proxy FTP (i.e. faire la
            connexion directement)
        -l, --lftp
            Se connecter avec lftp au lieu de ncftp. Le fonctionnement n'est pas
            garanti si l'on utilise un proxy FTP.
        -o OPTION
            Ajouter une option à la commande lancée. Si l'option prend un argument,
            il faut doubler l'option -o, e.g.
                authftp -l -o -e -o 'mirror remote local' host login pass
            Dans cet exemple, l'option -e de lftp est utilisée pour faire un miroir
            local du répertoire remote.
        --tls
            Indiquer que la connexion se fera en TLS. Implique --lftp puisque ncftp
            ne le supporte pas.

    note: A cause d'une limitation de lftp, ce n'est pas possible de se connecter
    automatiquement avec lftp si le mot de passe contient une virgule. A cause de la
    façon dont le proxy ftp est configuré, il n'est pas possible de se connecter
    avec un mot de passe qui contient le caractère @
    }}}

    {{{
    caturl: Afficher une url

    USAGE
        caturl <file.url|file.desktop|URL>

    OPTIONS
        -c, --check
            Vérifier que le fichier est valide
        -g, --get
            Attaquer l'url spécifiée avec curl
    }}}

    {{{
    compileAndGo: see http://Yost.com/computers/compileAndGo
    }}}

    {{{
    cssh: Faire une connexion ssh en lançant automatiquement un screen sur l'hôte distant

    USAGE
        cssh [user@]host [options]

    En principe, hormis l'argument user@host, il ne faudrait spécifier que des
    options. Dans le cas où d'autres arguments seraient spécifiés, les meilleurs
    efforts sont faits pour lancer ces commandes avant screen.
    }}}

    {{{
    doinplace: filtrer en place un fichier à travers une suite de commandes

    USAGE
        doinplace FILE COMMAND [ARGS...]

    Si on utilise une commande avec des options, penser à utliser '--' pour séparer
    les options de ce script des options de la commande

    En plus des commandes systèmes, il est possible d'utiliser toute fonction de
    nutools qui effectue des traitement sur un flux comme stripnl, filter_empty,
    merge_contlines, filter_comment, filter_conf, etc. Les fonctions nl2lf, nl2crlf,
    nl2cr, latin1compat et noaccents sont aussi disponibles par convenance.

    OPTIONS
        -p, --evalp
            Evaluer la commande avec evalp(), ce qui permet de chainer plusieurs
            commandes en les séparant par //. Cette option est automatiquement
            activée si ce script est lancé avec le nom doinplacex
        -g, --ignore-error, --replace-always
            Normalement, le fichier n'est pas remplacé si la commande retourne une
            erreur. Avec cette option, le fichier est remplacé quel que soit le code
            de retour de la commande. A utiliser par exemple avec des commandes
            comme grep qui peuvent retourner FAUX s'ils ne trouvent pas le motif.
            Cette option est automatiquement activée si ce script est lancé avec le
            nom doinplacef
    }}}

    {{{
    dumpclients: afficher les connexions TCP entrantes sur un port

    USAGE
        dumpclients [options] port

    OPTIONS
        -4, --only-tcp
        -6, --only-tcp6
            Se limiter au protocole spécifié. Par défaut, afficher toutes les
            connexions, qu'elles soient en IPv4 ou en IPv6
        -a, --all
            Afficher tous les sockets, y compris les ports d'écoute. Par défaut,
            seules les sockets ouvertes sont affichées.
        -n, --numeric
            Afficher uniquement les adresses IP au lieu du nom d'hôte.
        -z, --allow-no-port
            Ne pas exiger que le port soit spécifié
        --show none,ip,port,state
            Spécifier d'afficher comme informations supplémentaire: rien, l'adresse
            ip, le port et/ou l'état. Par défaut, afficher le port et l'état.
    }}}

    {{{
    Usage: /usr/bin/emacs [OPTION-OR-FILENAME]...

    Run Emacs, the extensible, customizable, self-documenting real-time
    display editor.  The recommended way to start Emacs for normal editing
    is with no options at all.

    Run M-x info RET m emacs RET m emacs invocation RET inside Emacs to
    read the main documentation for these command-line arguments.

    Initialization options:

    --batch                     do not do interactive display; implies -q
    --daemon                    start a server in the background
    --debug-init                enable Emacs Lisp debugger for init file
    --display, -d DISPLAY       use X server DISPLAY
    --no-desktop                do not load a saved desktop
    --no-init-file, -q          load neither ~/.emacs nor default.el
    --no-shared-memory, -nl     do not use shared memory
    --no-site-file              do not load site-start.el
    --no-splash                 do not display a splash screen on startup
    --no-window-system, -nw     do not communicate with X, ignoring $DISPLAY
    --quick, -Q                 equivalent to -q --no-site-file --no-splash
    --script FILE               run FILE as an Emacs Lisp script
    --terminal, -t DEVICE       use DEVICE for terminal I/O
    --user, -u USER             load ~USER/.emacs instead of your own

    Action options:

    FILE                    visit FILE using find-file
    +LINE                   go to line LINE in next FILE
    +LINE:COLUMN            go to line LINE, column COLUMN, in next FILE
    --directory, -L DIR     add DIR to variable load-path
    --eval EXPR             evaluate Emacs Lisp expression EXPR
    --execute EXPR          evaluate Emacs Lisp expression EXPR
    --file FILE             visit FILE using find-file
    --find-file FILE        visit FILE using find-file
    --funcall, -f FUNC      call Emacs Lisp function FUNC with no arguments
    --insert FILE           insert contents of FILE into current buffer
    --kill                  exit without asking for confirmation
    --load, -l FILE         load Emacs Lisp FILE using the load function
    --visit FILE            visit FILE using find-file

    Display options:

    --background-color, -bg COLOR   window background color
    --basic-display, -D             disable many display features;
                                      used for debugging Emacs
    --border-color, -bd COLOR       main border color
    --border-width, -bw WIDTH       width of main border
    --color, --color=MODE           override color mode for character terminals;
                                      MODE defaults to `auto', and can also
                                      be `never', `auto', `always',
                                      or a mode name like `ansi8'
    --cursor-color, -cr COLOR       color of the Emacs cursor indicating point
    --font, -fn FONT                default font; must be fixed-width
    --foreground-color, -fg COLOR   window foreground color
    --fullheight, -fh               make the first frame high as the screen
    --fullscreen, -fs               make first frame fullscreen
    --fullwidth, -fw                make the first frame wide as the screen
    --maximized, -mm                make the first frame maximized
    --geometry, -g GEOMETRY         window geometry
    --no-bitmap-icon, -nbi          do not use picture of gnu for Emacs icon
    --iconic                        start Emacs in iconified state
    --internal-border, -ib WIDTH    width between text and main border
    --line-spacing, -lsp PIXELS     additional space to put between lines
    --mouse-color, -ms COLOR        mouse cursor color in Emacs window
    --name NAME                     title for initial Emacs frame
    --no-blinking-cursor, -nbc      disable blinking cursor
    --reverse-video, -r, -rv        switch foreground and background
    --title, -T TITLE               title for initial Emacs frame
    --vertical-scroll-bars, -vb     enable vertical scroll bars
    --xrm XRESOURCES                set additional X resources
    --parent-id XID                 set parent window
    --help                          display this help and exit
    --version                       output version information and exit

    You can generally also specify long option names with a single -; for
    example, -batch as well as --batch.  You can use any unambiguous
    abbreviation for a --option.

    Various environment variables and window system resources also affect
    Emacs' operation.  See the main documentation.

    Report bugs to bug-gnu-emacs@gnu.org.  First, please see the Bugs
    section of the Emacs manual or the file BUGS.
    }}}

    {{{
    fconv: convertir un fichier ou les fichiers d'un répertoire

    USAGE
        fconv -f FILE [cmds...]
        fconv FILE [cmds...]

    Une ou plusieurs commandes peuvent être spécifiées, séparées par //
    La commande par défaut est 'lf'
    Si des commandes utilisant des options sont utilisées, penser à séparer les
    options de fconv avec --

    OPTIONS
        -N, --detect-always
            Pour la commande conv, ne pas optimiser le calcul de l'encoding. Cette
            option n'est valide que si src_enc n'est pas spécifié. On assume que
            tous les fichiers n'ont pas le même encoding: l'encoding src_enc est
            donc recalculé à chaque fois.
        -r, --reverse
            Pour la commande conv, inverser src_enc et dest_enc, qui doivent être
            tous les deux spécifiés.
        -f, --file FILE
            Spécifier le fichier ou le répertoire concerné par la conversion. Les
            aliases -d et --dir sont aussi reconnus.
            Si cette option n'est pas spécifiée, le premier argument est considéré
            comme le nom du fichier ou du répertoire à convertir. Par défaut,
            convertir l'entrée standard.
            Si un répertoire est spécifié, tous les fichiers de ce répertoire et de
            ses sous-répertoires sont recherchés de façon récursive, sans limite de
            profondeur. Ensuite, chacun de ces fichiers est converti.
        --show-cmd
            Afficher la commande qui serait exécutée

    COMMANDES
        c, conv dest_enc [src_enc]
            Convertir le fichier dans un autre encoding.
            dest_enc est l'encoding destination. Il doit être spécifié.
            src_enc est l'encoding source. S'il n'est pas spécifié ou vaut 'detect',
                il est autodétecté.
        U, utf8 [src_enc]
            Equivalent à conv utf8 src_enc
        L, latin1 [src_enc]
            Equivalent à conv latin1 src_enc
        lf
        crlf
        cr
            Convertir respectivement les caractères de fin de ligne en LF, CR/LF ou CR
        lc, latin1compat
            Transformer certains caratères UTF-8 en équivalents qui existent en Latin1
        na, noaccents
            Transformer les caractères accentués en caractères non accentués
        sort [-u]
            Trier le fichier avec la commande sort. Attention! Il ne faut utiliser
            que les options de sort qui agissent sur un flux e.g. -u pour trier les
            lignes de façon unique.
    }}}

    {{{
    fnconv: renommer un fichier ou les fichiers d'un répertoire

    USAGE
        fnconv -f FILE [cmds...]
        fnconv FILE [cmds...]

    Une ou plusieurs commandes peuvent être spécifiées, séparées //
    La commande par défaut est 'fixcase'

    OPTIONS
        -N, --detect-always
            Pour la commande conv, ne pas optimiser le calcul de l'encoding. Cette
            option n'est valide que si src_enc n'est pas spécifié. On assume que
            tous les fichiers n'ont pas le même encoding: l'encoding src_enc est
            donc recalculé à chaque fois.
        -r, --reverse
            Pour la commande conv, inverser src_enc et dest_enc, qui doivent être
            tous les deux spécifiés.
        -f, --file FILE
            Spécifier le fichier ou le répertoire concerné par le renommage. Les
            aliases -d et --dir sont aussi reconnus.
            Si cette option n'est pas spécifiée, le premier argument est considéré
            comme le nom du fichier ou du répertoire à renommer.
            Si un répertoire est spécifié, le traitement est appliqué à tous les
            fichiers et répertoires de façon récursive, sans limite de profondeur.
        --show-cmd
            Afficher la commande qui serait exécutée

    COMMANDES
        C, conv dest_enc [src_enc]
            Convertir le nom du fichier dans un autre encoding.
            dest_enc est l'encoding destination. Il doit être spécifié.
            src_enc est l'encoding source. S'il n'est pas spécifié ou vaut 'detect',
                il est autodétecté.
        U, utf8 [src_enc]
            Equivalent à conv utf8 src_enc
        L, latin1 [src_enc]
            Equivalent à conv latin1 src_enc
        lc, latin1compat
            Transformer certains caratères UTF-8 en équivalents qui existent en Latin1
        na, noaccents
            Transformer les caractères accentués en caractères non accentués
        l, lowercase
            Transfomer le nom en minuscule
        u, uppercase
            Transformer le nom en majuscule
        f, fixcase
            Transformer le nom en minuscule s'il est entièrement en majuscule
    }}}

    {{{
    geturl: Télécharger un fichier avec wget ou curl

    USAGE
        geturl <file.url|file.desktop|URL> [wget options]
    }}}

    {{{
    mkRewriteRules: Créer un fichier de redirections pour Apache à partir d'un certain
    nombre de règles

    USAGE
        mkRewriteRules -f rewrite.rules [-o RewriteRules.conf] [-w RewriteRules.html] host

    OPTIONS
        -p  Générer les directives <Proxy...> et tenir compte de proxy_acls
            Par défaut, le champ proxy_acls est ignoré

    FORMAT des règles de mapping
    ============================

    Les commentaires commencent par le signe "#"
    Les règles sont de la forme:
        src:dest:host:suffix:OPTS:prot:proxy_acls
        ^prefix
        =literal

    prot vaut par défaut http. Il peut valoir aussi https

    Si dest ou suffix se terminent par $, on est en mode NO_SLASH
    En mode NO_SLASH, si src se termine par $, on est en mode NO_TRAIL

    * Si dest est de la forme Application.woa
    En mode NO_SLASH, on génère
        RewriteRule ^/src(.*) [prot://host]/cgi-bin/WebObjects/dest[/suffix]$1 [L,OPTS]
    En mode NO_SLASH+NO_TRAIL, on génère
        RewriteRule ^/src [prot://host]/cgi-bin/WebObjects/dest[/suffix] [L,OPTS]
    En mode normal, on génère
        RewriteRule ^/src$ /src/
        RewriteRule ^/src/(.*) [prot://host]/cgi-bin/WebObjects/dest[/suffix]/$1 [L,OPTS]

    * Si dest n'est pas de la forme Application.woa
    En mode NO_SLASH, on génère
        RewriteRule ^/src(.*) [prot://host]/dest[/suffix]$1 [L,OPTS]
    En mode NO_SLASH+NO_TRAIL, on génère
        RewriteRule ^/src [prot://host]/dest[/suffix] [L,OPTS]
    En mode normal, on génère
        RewriteRule ^/src$ /src/
        RewriteRule ^/src/(.*) /dest[/suffix]/$1 [L,OPTS]

    Si une règle est précédée d'une ou plusieurs lignes de la forme "^prefix",
    ces lignes sont copiées avant chacune des commandes RewriteRule générées
    pour une règle. Ceci permet d'ajouter des conditions avec RewriteCond pour
    une règle. e.g.
        ^RewriteCond %{REMOTE_ADDR} 10\..*
        src:dest.woa
    qui génère:
        RewriteCond %{REMOTE_ADDR} 10\..*
        RewriteRule ^/src$ /src/
        RewriteCond %{REMOTE_ADDR} 10\..*
        RewriteRule ^/src/(.*) /cgi-bin/WebObjects/dest.woa/$1 [L]

    Une ligne de la forme "=literal" est recopiée sans modifications (sans le "=")
    dans le fichier de sortie.

    proxy_acls est utilisé si l'option -p est spécifiée et OPTS contient P (comme
    proxy), ou si le mode de réécriture requière l'utilisation d'un proxy.

    * Avec la valeur "None", aucune directive <Proxy> n'est générée
    * Si aucune valeur n'est spécifiée, la directive suivante est générée:
      <Proxy $URL>
        AddDefaultCharset off
        Order Deny,Allow
        Allow from all
      </Proxy>
    * Si une valeur est spécifiée, la directive suivante est générée:
      <Proxy $URL>
        AddDefaultCharset off
        Order Allow,Deny
        Allow from $proxy_acls
      </Proxy>

    Dans les exemples donnés ci-dessus, $URL est l'url générée par la réécriture,
    et $proxy_acls la valeur du champ proxy_acls spécifiée ci-dessus.
    }}}

    {{{
    mkiso: créer une image iso d'un répertoire

    USAGE
        mkiso [options] srcdir [dest.iso]

    OPTIONS
        -M, --hfs
            créer une image hybride ISO/HFS
        -V, --volume
            Nom du volume. Par défaut, prendre le nom de base du répertoire
            d'origine. La taille est de 32 caractères max.
        -A, --application
            Description de l'application qui est sur l'image créée. Par défaut,
            prendre le nom de base du répertoire d'origine. La taille est de 128
            caractères max.
    }}}

    {{{
    mkurl: Enregistrer une url dans un fichier raccourci

    USAGE
        mkurl <url> [output]

    OPTIONS
    Par défaut, l'url est enregistrée dans un fichier homepage.url
    Mais il est possible de spécifier un fichier avec l'extension .url pour un
    raccourci utilisable aussi sous Windows, ou avec l'extension .desktop pour
    compatibilité avec le standard XDG
    }}}

    {{{
    mkusfx: Créer une archive auto-extractible qui installe son contenu avec uinst

    USAGE
        mkusfx [options] [--bare] src cmd...
        mkusfx [options] [--uinst] src

    OPTIONS
        --bare
            Installer le contenu de l'archive en lançant la commande 'cmd...' avec
            le répertoire courant étant le contenu de l'archive. Typiquement, ce
            sera une commande de forme './script', où script est un fichier situé à
            la racine de l'archive
            Dans ce mode d'installation, l'option --self-contained est ignorée.
        --uinst
            Installer le contenu de l'archive avec uinst (par défaut)
        -o dest
            Spécifier le fichier de sortie. Par défaut, il s'agit de
            ${src}-installer.run
        --tmp-archive
            Spécifier qu'il s'agit d'une archive temporaire. Cette archive
            s'auto-détruit après utilisation.
        --self-contained
            Spécifier que l'archive doit pouvoir s'installer même sur un système sur
            lequel nutools n'est pas installé. Cette archive contiendra une copie
            locale de ulib et uinst.sh
    }}}

    {{{
    mocifs: Monter un partage Windows/Samba/CIFS

    USAGE
        mocifs [user@]host[/path] [mountpoint]

    Par défaut, le répertoire distant est montée sur un répertoire avec le même nom
    de base que l'hôte. Si le répertoire distant est déjà monté, il est démonté.
    Les options -M et -U permettent de modifier le comportement par défaut.

    OPTIONS
        -M
            Forcer le montage
        -U
            Forcer le démontage
        -o OPTIONS
            Ajouter les options spécifiées à la commande de montage mount.cifs
        -u USERNAME
        -p PASSWORD
        -c USERNAME:PASSWORD
            Spécifier les credentials à utiliser pour la connexion
    }}}

    {{{
    modav: Monter un répertoire sur un hôte distant avec davfs

    USAGE
        modav http[s]://host[/path] [mountpoint]

    Par défaut, le répertoire distant est montée sur un répertoire avec le même nom
    de base que l'hôte. Si le répertoire distant est déjà monté, il est démonté.
    Les options -M et -U permettent de modifier le comportement par défaut.

    OPTIONS
        -M
            Forcer le montage
        -U
            Forcer le démontage
        -o OPTIONS
            Ajouter les options spécifiées à la commande de montage
        -u USERNAME
        -p PASSWORD
        -c USERNAME:PASSWORD
            Si les credentials à utiliser ne sont pas configuré dans le fichier
            /etc/davfs2/secrets, cette option permet de les spécifier. Si cette
            option est utilisée, il est possible de rajouter
                ask_auth 0
            dans le fichier /etc/davfs2/davfs2.conf pour éviter le conflit qui se
            produit quand des informations sont demandées interactivement. C'est le
            cas par exemple si une connexion en https est faite et que la chaine de
            certification n'est pas configurée. Pour mémoire, cela se fait avec
                servercert myCAs.pem
            dans le fichier /etc/davfs2/davfs2.conf
            Bien entendu, il est préférable de configurer les credentials dans le
            fichier /etc/davfs2/secrets avec la syntaxe
                url         username    password
            ou
                mountpoint  username    password
    }}}

    {{{
    moiso: Monter une image ISO

    USAGE
        moiso image.iso [mountpoint]

    Par défaut, l'image iso est montée sur un répertoire avec le même nom de base.
    Si l'image est déjà montée, elle est démontée. Les options -m et -u permettent
    de modifier le comportement par défaut.

    OPTIONS
        -m
            Forcer le montage
        -u
            Forcer le démontage
    }}}

    {{{
    mossh: Monter un répertoire sur un hôte distant avec sshfs

    USAGE
        mossh [user@]host[:/path] [mountpoint]

    Par défaut, le répertoire distant est montée sur un répertoire avec le même nom
    de base que l'hôte. Si le répertoire distant est déjà monté, il est démonté.
    Les options -M et -U permettent de modifier le comportement par défaut.

    OPTIONS
        -M
            Forcer le montage
        -U
            Forcer le démontage
        -o OPTIONS
            Ajouter les options spécifiées à la commande de montage
        -s
            Equivalent à -o allow_other ou -o allow_root selon que l'on est root ou
            non
        -u USER
            Spécifier le user pour la connexion distante, s'il n'est pas possible de
            le spécifier dans l'url. En cas de conflit, la valeur dans l'url est
            prioritaire par rapport à cette option.
    }}}

    {{{
    mysqlcsv: Faire une requête MySQL et formater la sortie pour traitement avec awkcsv

    USAGE
        mysqlcsv [query [db]] [-- mysql options]

    query   est la requête sql à exécuter. Si query n'est pas spécifiée, la(les)
            requête(s) sql sont prises sur l'entrée standard, ou depuis un fichier
            si l'option -f est spécifiée.
    db      est le nom de la base de données. Cette argument n'est lu que si le nom
            de la base de donnée n'est ni spécifié dans le fichier de configuration,
            ni spécifié avec l'option -D

    OPTIONS
        -h, --host HOST
        -P, --port PORT
        -u, --user USER
        -pPASSWORD
        -D, --database DATABASE
            Informations de connexion à la base de données
        -C, --config CONFIG
            Prendre les informations de connexion depuis le fichier spécifié.
            Le fichier doit être de la forme
                host=HOST
                #post=3306
                user=USER
                password=PASS
                #database=DB
                #query=QUERY
            Les variables port, database et query sont facultatives.
            Les valeurs définies dans ce fichier sont prioritaires par rapport à
            celles qui auraient été spécifiées sur la ligne de commande.
            Utiliser password=--NOT-SET-- s'il faut se connecter sans mot de passe
            Cette option peut être utilisée plusieurs fois, auquel cas les fichiers
            sont chargés dans l'ordre.
        --profile PROFILE
            La variable $PROFILE est définie avec la valeur spécifiée avant de
            sourcer les fichiers de configuration. Cela permet d'avoir des fichiers
            de configuration qui calculent dynamiquement les paramètres en fonction
            de la valeur du profil.
        -N, --no-headers
            Ne pas afficher les en-têtes
        -c, --force
            Continuer le traitement même en cas d'erreur
        -r, --raw
            Ne pas autoriser mysql à mettre en échappement certaines valeurs
            retournées par le serveur. Par défaut, les transformations suivantes
            sont effectuées:
                newline --> \n
                tab     --> \t
                nul     --> \0
                \      --> \\
        -n, --nulls
            Transformer dans le flux en sortie les valeurs NULL en chaines vides
        -f, --input INPUT
            Lire la requête depuis le fichier input au lieu de le lire depuis la
            ligne de commande ou l'entrée standard. Ne pas spécifier cette option
            ou utiliser '-' pour lire depuis l'entrée standard.
            Cette option est ignorée si la requête est spécifiée parmi les
            arguments.
    }}}

    {{{
    mysqlloadcsv: Charger une table MySQL avec un fichier csv

    USAGE
        mysqlloadcsv [db.]table [fields...] [-- mysql options]

    db      est le nom de la base de données
    table   est le nom de la table à charger
    fields  est la liste des colonnes. Si cette valeur est spécifiée, il faudra
            peut-être utiliser l'option -s pour ignorer le cas échéant la ligne des
            en-têtes dans le fichier en entrée. Sinon, les colonnes à utiliser sont
            calculées à partir du fichier en entrée.

    Dans les données en entrées, qui doivent être en UTF8, les conversions suivantes
    sont effectuées par MySQL:

        \0 --> <caractère NUL>
        \b --> <backspace>
        \n --> <newline>
        \r --> <carriage return>
        \t --> <tab>
        \Z --> Ctrl+Z
        \N --> NULL

    OPTIONS
        -h, --host host
        -P, --port port
        -u, --user user
        -ppassword
            Informations de connexion à la base de données
        -C, --config CONFIG
            Prendre les informations de connexion depuis le fichier spécifié.
            Le fichier doit être de la forme
                host=HOST.TLD
                #post=3306
                user=USER
                password=PASS
                #dbtable=DB.TABLE
                #fields=(FIELDS...)
                # Il est possible aussi de spécifier DB et TABLE séparément:
                #database=DB
                #table=TABLE
            Les variables port, dbtable et fields sont facultatives.
            Les valeurs définies dans ce fichier sont prioritaires par rapport à
            celles qui auraient été spécifiées sur la ligne de commande.
            Utiliser password=--NOT-SET-- s'il faut se connecter sans mot de passe
            Cette option peut être utilisée plusieurs fois, auquel cas les fichiers
            sont chargés dans l'ordre.
        --profile PROFILE
            La variable $PROFILE est définie avec la valeur spécifiée avant de
            sourcer les fichiers de configuration. Cela permet d'avoir des fichiers
            de configuration qui calculent dynamiquement les paramètres en fonction
            de la valeur du profil.
        -f, --input INPUT
            Fichier en entrée. Ne pas spécifier cette option ou utiliser '-' pour
            lire depuis l'entrée standard.
        -d, --auto-dbtable DB
            Spécifier la base de données avec laquelle se connecter. De plus, si le
            nom de la table n'est pas spécifié, prendre par défaut le nom de base du
            fichier spécifié avec l'option -f
        -s, --skip-lines NBLINES
            Nombre de lignes à sauter dans le fichier en entrée
        -n, --fake
            Ne pas effectuer l'opération. Afficher simplement la commande SQL.
        --run
            Forcer le lancement de l'opération. Utiliser cette option avec -A pour
            créer la table avec les paramètres analysés.
        -T, --truncate
            Vider la table avant d'effectuer le chargement
        -L, --load-data
            Charger les données avec la commande 'load data local'. C'est l'option
            par défaut. Le fichier est transmis tel quel à MySQL.
        -I, --insert-data
            Charger les données en générant des commandes 'insert into'. L'effet est
            en principe le même avec l'option -L (sauf que certains formats de date
            exotiques seront correctement importés). Cette option peut aussi être
            utilisée avec l'option -n pour générer une liste de commande à corriger
            et/ou adapter.
        -U, -k, --update-data KEY
            Au lieu de charger de nouvelles données, essayer de mettre à jour la
            table. KEY est le nom de la colonne qui est utilisée comme clé. Toutes
            les autres colonnes sont les nouvelles données à mettre à jour. Si
            aucune ligne ne correspond à une clé donnée, la mise à jour pour cette
            ligne est ignorée.
            Note: utiliser les options -T et -U ensemble n'a pas de sens, mais -T
            est quand même honoré.
        -Z, --null-value VALUE
            Avec les options -I et -U, considérer que NULL est représenté par la
            chaine spécifiée. Par défaut, utiliser \N
        -z, --null-is-empty
            Avec les options -I et -U, considérer que NULL est représenté par la
            chaine vide. Cette option est équivalente à -Z ''
        -t, --types [DEFAULT_TYPE,]FIELD:TYPE,...
            Spécifier pour chaque champ mentionné le type de donnée à forcer. Le
            type 'auto' signifie que le type est autodétecté. C'est la valeur par
            défaut. Les autres types valides sont 'str', 'int' et 'date'
            Cette option est ignorée avec l'option -L
        -A, --analyse
            Analyser les données et afficher une requête pour créer une table qui
            pourrait contenir ces données.
            Cette option implique --fake et affiche simplement la commande SQL.
            Pour lancer la commande SQL générée, il faut ajouter l'option --run
            APRES cette option
    }}}

    {{{
    noerr: lancer une commande en supprimant la sortie d'erreur
    }}}

    {{{
    noerror: lancer une commande en masquant son code de retour. le code de retour est toujours 0
    }}}

    {{{
    noout: lancer une commande en supprimant la sortie standard
    }}}

    {{{
    nutools: configurer ou afficher des informations sur nutools

    USAGE
        nutools [VERSION]

    OPTIONS
        -C, --configure
            Faire la configuration pour l'utilisateur courant en appelant uenv -u
            Avec cette option, l'option -l (ou --local-profiles) est aussi reconnue
            et est passée directement à uenv
        -v, --version
            Afficher la version de nutools installée. C'est l'option par défaut
        -c, --check
            Calculer si la version installée correspond à la version spécifiée
        -o, --oper OPERATOR
            Spécifier l'opérateur à utiliser avec l'option --check (par défaut,
            utiliser l'opérateur ge, qui permet de vérifier si la version minimum
            spécifiée est installée)
        --eq
        --ne
        --lt
        --le
        --gt
        --ge
        --same
        --diff
            Ces options sont des raccourcis. L'option '--OP' est équivalente à
            '--check --op OP'
    }}}

    {{{
    openurl: Ouvrir une URL dans un navigateur

    USAGE
        openurl <file.url|file.desktop|URL>
    }}}

    {{{
    pdev: basculer sur une branche de développement

    USAGE
        pdev [FEATURE [SOURCE]]
        pdev -m|-l|-d [FEATURE]

    - Vérifier l'existence de la branche develop. La créer si nécessaire en la
      basant sur [origin/]master.
    - Vérifier s'il n'y a pas de modifications locales. Sinon, proposer de faire un
      commit ou un stash.
    - Si FEATURE est spécifié, et si on n'est pas déjà sur cette branche, basculer
      vers cette nouvelle branche. S'il s'agit d'une nouvelle branche, la baser sur
      la branche SOURCE, qui vaut par défaut develop
    - Si FEATURE n'est pas spécifié, basculer sur develop s'il s'agit de la seule
      solution, sinon afficher un menu pour choisir la branche de destination.

    OPTIONS
        -C, --projdir PROJDIR
            Spécifier le répertoire de base du projet qui est dans git. Par défaut,
            on travaille dans le répertoire courant et on laisse git trouver le
            répertoire de base du projet. Avec cette option, le répertoire courant
            est modifié avant de lancer les commandes git.
        -O, --origin ORIGIN
            Spécifier le nom de l'origine. Par défaut, utiliser 'origin'
        -o, --offline
            En cas de création d'une branche, ne pas pousser vers l'origine; ne pas
            tenter le cas échéant de traquer la branche dans l'origine; ne pas
            supprimer une branche dans l'origine. Cette option est automatiquement
            activée si la variable UTOOLS_VCS_OFFLINE est définie.
        --online
            Annuler l'effet de la variable UTOOLS_VCS_OFFLINE: forcer le mode online
        --sync
            Faire un certain nombre d'opération pour 'corriger' le dépôt local: pour
            chacune des branches distantes, vérifier qu'il existe une branche locale
            qui la traque, et pour chaque feature branche locale, vérifier qu'il
            existe une branche distante associée. Cette option nécessite --online

        -s, --squash COMMIT_MSG
            Si la branche actuelle est une feature branch, la merger comme un seul
            commit avec le message COMMIT_MSG dans develop puis la supprimer. Puis
            basculer sur la branche develop.
            Cette option ne devrait pas être utilisée avec -k, puisque bien que les
            modifications soient mergées, la branche elle-même n'est pas considérée
            comme mergée. Les résultats sont donc indéfinis si la branche est mergée
            à plusieurs reprises.
        -b, --rebase
            Si la branche actuelle est une feature branch, lancer 'git rebase -i'
            sur la feature branch. Cela permet de réordonner les commits pour
            nettoyer l'historique avant de fusionner la branche avec -m
            Cette option devrait le cas échéant être utilisée immédiatement avant -m
            ou alors il faut forcer le push et communiquer avec l'équipe sur le fait
            que la branche de feature a été rebasée.
        -m, --merge
            Si la branche actuelle est une feature branch, la merger dans develop
            puis la supprimer. Puis basculer sur la branche develop.
        --merge-log
            Ajouter un résumé des modifications sur la feature branch en ajoutant le
            log en une ligne de chaque commit dans le message du merge. Cette option
            n'est en principe pas nécessaire puisque 'prel -um' intègre la liste des
            commits dans CHANGES.txt
        -k, --keep
            Avec l'option -m, ne pas supprimer une feature branch après l'avoir
            fusionnée dans develop. Cela permet d'intégrer les modifications petit à
            petit.
        --delete
            Supprimer une feature branch, à condition qu'elle aie déjà été
            entièrement fusionnée dans la branch develop
        --force-delete
            Supprimer une feature branch, même si elle n'a pas encore été fusionnée
            dans la branche develop

        -l, --log
        -d, --diff
            Afficher les modifications entre deux branches. L'option --log affiche
            les modifications dans l'ordre alors que --diff affiche les différences
            sous forme de diff. Les deux options peuvent être combinées et ont
            l'effet de 'git log -p'
            La branche comparée, s'il elle n'est pas spécifiée, est par défaut la
            branche courante. S'il s'agit d'une feature branch, elle est comparée à
            develop. S'il s'agit de la branche develop, elle est comparée à master.
    }}}

    {{{
    prel: basculer sur une branche de release

    USAGE
        prel -u [SOURCE]
        prel -c [RELEASE [SOURCE]]
        prel -m|-l|-d [RELEASE]

    - Vérifier s'il n'y a pas de modifications locales. Sinon, proposer de faire un
      commit ou un stash.
    - Avec l'option -c, s'il existe une branche de release, proposer de basculer
      vers elle ou sur la branche master. Sinon, basculer sur la branche master.
    - Avec l'option -u, proposer ou fixer une branche de release à créer. Si elle
      existe déjà, basculer vers elle. Sinon, la créer en la basant sur SOURCE, qui
      vaut par défaut develop

    OPTIONS
        -C, --projdir PROJDIR
            Spécifier le répertoire de base du projet qui est dans git. Par défaut,
            on travaille dans le répertoire courant et on laisse git trouver le
            répertoire de base du projet. Avec cette option, le répertoire courant
            est modifié avant de lancer les commandes git.
        -O, --origin ORIGIN
            Spécifier le nom de l'origine. Par défaut, utiliser 'origin'
        -o, --offline
            En cas de création d'une branche, ne pas pousser vers l'origine; ne pas
            tenter le cas échéant de traquer la branche dans l'origine; ne pas
            supprimer une branche dans l'origine. Cette option est automatiquement
            activée si la variable UTOOLS_VCS_OFFLINE est définie.
        --online
            Annuler l'effet de la variable UTOOLS_VCS_OFFLINE: forcer le mode online

        -c, --checkout
            Basculer vers une branche de release existante. C'est l'option par
            défaut. Si aucune branche de release n'existe, basculer vers master
        -u, --update
            Préparer une nouvelle release. Utiliser une des options -x, -z ou -p
            pour spécifier le type de release à préparer. Si la branche qui serait
            créée pour le type de release existe déjà, basculer vers cette branche.
            S'il faut la créer, la baser sur la branche SOURCE, qui vaut par défaut
            develop
        --menu
        -x, --major
        -z, --minor
        -p, --patchlevel
            Utilisé avec l'option -u, soit afficher un menu pour choisir la version
            de la nouvelle release (par défaut), soit préparer respectivement une
            release majeure, mineure, ou pour correction de bug.
        -v-OPT
            Avec l'option -u, spécifier une option de pver permettant de choisir la
            version de la nouvelle release. Les options supportées sont -v, -l, -a,
            -b, -r et -R. Par exemple, si la version actuelle sur la branche master
            est 0.2.3, les options '-uz -v-lbeta' permettent de préparer la release
            0.3.0-beta
            En principe, cette option n'a pas à être utilisée, puisque dans une
            branche de release, on peut faire vivre les versions de pré-release
            jusqu'à la release finale. Ainsi, la branche de release est nommée
            d'après la version finale, mais le projet peut recevoir une version de
            pré-release incrémentale.
        -w, --write
            Si une nouvelle branche est créée avec -u, mettre à jour le fichier
            VERSION.txt avec pver. C'est l'option par défaut.
        -n, --no-write
            Si une nouvelle branche est créée avec -u, NE PAS mettre à jour le
            fichier VERSION.txt avec pver. Utiliser cette option si la mise à jour
            du numéro de version doit être faite d'une manière particulière.
        -e, --edit
            Editer le fichier CHANGES.txt autogénéré par -u -w
            Cette option est surtout utile si -m est utilisé avec -u, pour donner la
            possibilité de corriger la liste des modifications avant leur
            enregistrement définitif.

        -m, --merge
            Si la branche actuelle est une branche de release, ou s'il existe une
            branche de release, la merger dans master, puis dans develop, puis la
            supprimer. Puis basculer sur la branche master.
            S'il n'existe pas de branche de release, proposer de fusionner les
            modifications de la branche develop dans la branche master, sans
            préparer de branche de release au préalable.
        --delete
            Supprimer une branche de release, à condition qu'elle aie déjà été
            entièrement fusionnée dans la branch master
        --force-delete
            Supprimer une branche de release, même si elle n'a pas encore été
            fusionnée dans la branche master

        -s, --summary
            Afficher la liste des différences entre la branche develop et la branche
            master, comme elle serait générée par les options -u -w pour le fichier
            CHANGES.txt
        -l, --log
            Afficher les modifications actuellement effectuée dans la branche de
            release par rapport à develop.
        -d, --diff
            Afficher les modifications actuellement effectuée dans la branche de
            release par rapport à develop, sous forme de diff.
    }}}

    {{{
    pver: gérer des numéros de version selon les règles du versionage sémantique v2.0.0 (http://semver.org/)

    USAGE
        pver [options]

    OPTIONS
        -f, --file VERSIONFILE
            Gérer le numéro de version se trouvant dans le fichier spécifié. Le
            fichier est créé si nécessaire. C'est l'option par défaut si un fichier
            nommé VERSION.txt se trouve dans le répertoire courant.
        -e, --maven POMFILE
            Gérer le numéro de version se trouvant dans le fichier pom.xml spécifié.
            Le fichier DOIT exister. C'est l'option par défaut si un fichier nommé
            pom.xml se trouve dans le répertoire courant.
        -F, --file-string VERSIONFILE
            Prendre pour valeur de départ le contenu du fichier VERSIONFILE (qui
            vaut par défaut VERSION.txt)
        -g, --git-string [branch:]VERSIONFILE
            Prendre pour valeur de départ le contenu du fichier VERSIONFILE (qui
            vaut par défaut VERSION.txt) dans la branche BRANCH (qui vaut par défaut
            master) du dépôt git situé dans le répertoire courant.
        -s, --string VERSION
            Prendre pour valeur de départ le numéro de version spécifié

        --show
            Afficher le numéro de version. C'est l'action par défaut
        --allow-empty
            Supporter que la version puisse ne pas être spécifiée ni trouvée. Dans
            ce cas, ne pas assumer que la version effective est 0.0.0
            Avec --show et --update, ne rien afficher si la version est vide.
        --check
            Vérifier que le numéro de version est conforme aux règles du versionage
            sémantique
        --convert
        --no-convert
            Activer (resp. désactiver) la conversion automatique.  Par défaut, si la
            version est au format classique 'x.z[.p]-rDD/MM/YYYY', elle est
            convertie automatiquement au format sémantique x.z.p+rYYYYMMDD
        --eq VERSION
        --ne VERSION
        --lt VERSION
        --le VERSION
        --gt VERSION
        --ge VERSION
        --same VERSION
        --diff VERSION
            Comparer avec la version spécifiée. Les opérateurs --eq, --ne, --lt,
            --le, --gt, et --ge ignorent l'identifiant de build (comme le demande la
            règle du versionage sémantique). Les opérateurs --same et --diff
            comparent aussi les identifiants de build.
        -v, --set-version VERSION
            Spécifier un nouveau numéro de version qui écrase la valeur actuelle.
            Cette option ne devrait pas être utilisée en temps normal parce que cela
            va contre les règles du versionage sémantique.
        --prel
            Spécifier un nouveau numéro de version qui écrase la valeur actuelle. Le
            numéro de version est obtenu à partir du nom de la branche git courante,
            qui doit être de la forme release-VERSION
        -u, --update
            Mettre à jour le numéro de version.

        --menu
            Afficher un menu permettant de choisir le composant de la version à
            incrémenter
        -x, --major
            Augmenter le numéro de version majeure
        -z, --minor
            Augmenter le numéro de version mineure. C'est la valeur par défaut.
        -p, --patchlevel
            Augmenter le numéro de patch

        -l, --prelease ID
            Spécifier un identifiant de pré-release, à ajouter au numéro de version.
        -a, --alpha
        -b, --beta
        -r, --rc
            Spécifier une pré-release de type alpha, beta, ou rc. Si la version est
            déjà dans ce type, augmenter la dernière valeur numérique des composants
            de l'identifiant, e.g. alpha deviant alpha.1, beta-1.2 devient beta-1.3,
            rc1 devient rc2
            XXX ces fonctions ne sont pas encore implémentées
        -R, --final, --release
            Supprimer l'identifiant de prérelease

        -m, --metadata ID
            Spécifier un identifiant de build, à ajouter au numéro de version.
        -M, --vcs-metadata
            Spécifier l'identifiant à partir de la révision actuelle dans le
            gestionnaire de version. Note: pour le moment, seul git est supporté.
        --add-metadata ID
            Ajouter l'identifiant spécifié à la valeur actuelle, au lieu de la
            remplacer. Séparer l'identifiant de la valeur précédente avec un '.'
    }}}

    {{{
    pz: faire une archive du projet

    USAGE
        pz

    OPTIONS
        -C, --projdir PROJDIR
            Spécifier le répertoire de base du projet qui est dans git. Par défaut,
            on travaille dans le répertoire courant et on laisse git trouver le
            répertoire de base du projet. Avec cette option, le répertoire courant
            est modifié avant de lancer les commandes git.
        -d, --destdir DESTDIR
            Spécifier le répertoire dans lequel générer l'archive. Par défaut,
            prendre le répertoire parent du répertoire de base du dépôt.
    }}}

    {{{
    Usage: reptyr [-s] PID
           reptyr -l|-L [COMMAND [ARGS]]
      -l    Create a new pty pair and print the name of the slave.
               if there are command-line arguments after -l
               they are executed with REPTYR_PTY set to path of pty.
      -L    Like '-l', but also redirect the child's stdio to the slave.
      -s    Attach fds 0-2 on the target, even if it is not attached to a tty.
      -h    Print this help message and exit.
      -v    Print the version number and exit.
      -V    Print verbose debug output.
    }}}

    {{{
    rmtildes: supprimer les fichiers *~ dans le répertoire courant

    USAGE
        rmtildes [dir [glob]]

    Par défaut, dir==. et glob==*~
    }}}

    {{{
    rruns: Déploiement distant avec runs

    USAGE
        rruns [-h hosts] [-T tmproot] rscriptname name=value...
        rruns [-h hosts] [-T tmproot] @recipe name=value...
        rruns [-h hosts] [-T tmproot] -f rscript name=value...
        rruns [-h hosts] [-T tmproot] -r recipe name=value...

    Lancer ce script sans argument (hors options) est équivalent à le lancer avec
    l'argument @default

    OPTIONS
        -C  Ne pas faire le déploiement. Configurer uniquement la connexion par clé
            sur les hôtes distants spécifiés pour le user spécifié. Il faut pouvoir
            se connecter par mot de passe pour configurer la connexion par clé.
            Si l'on veut configurer la connexion par clé pour le user root, mais que
            ce n'est pas possible de se connecter par mot de passe avec le user root
            sur l'hôte distant, et qu'il existe un user sudoer sur l'hôte distant,
            il est possible de faire la configuration avec '--configure root'. La
            commande serait alors
                rruns -h user@host --configure root
        -T tmproot
            Spécifier le répertoire temporaire sur l'hôte distant, comme par exemple
            /var/tmp. Cette option est utile pour les vservers, qui ont par défaut
            un /tmp minuscule de 16 Mo.
        -S ssh
            Spécifier le programme à utiliser pour la connection par ssh.
        -h host
        -h @hostsfile
            Spécifier un ou plusieurs hôtes sur lequels faire le déploiement. Pour
            spécifier plusieurs hôtes, il est possible d'utiliser plusieurs fois
            l'option -h, ou spécifier en une seule fois plusieurs hôtes en les
            séparant par un espace ou le caractère ':', e.g. 'host1 host2' ou
            'host1:host2'. Si la spécification contient les caractères { et },
            l'expansion est effectuée, e.g
                -h 'root@{host1,host2}.univ.run'
            Par défaut, la connexion sur l'hôte distant se fait avec l'utilisateur
            root. Il est possible de spécifier un autre utilisateur avec la syntaxe
            user@host, e.g -h user@host
            La forme @hostsfile permet de lire la liste des hôtes depuis le fichier
            hostsfile, à raison d'un hôte par ligne.
            Si cette option n'est pas spécifiée, et que le répertoire courant est
            dans un des répertoires de $RUNSHOSTSPATH, sélectionner l'hôte
            correspondant. Sinon, l'utilisateur doit saisir l'hôte distant de façon
            interactive.
        -f RSCRIPT
            Lancer le script individuel spécifié au lieu de chercher dans les
            répertoires $RUNS{SCRIPTS,HOSTS}PATH
        -r RECIPE
            Lancer les scripts spécifiés dans le fichier de recettes individuel
            spécifié.
        -z  Forcer la réinstallation des scripts qui se basent sur shouldrun/setdone
        -o OUTPUT
            Générer l'archive à lancer sur l'hôte distant au lieu de faire le
            déploiement. Si plusieurs hôtes sont spécifiés, OUTPUT est considéré
            comme un nom de base auquel est ajouté le nom de l'hôte sur lequel
            l'archive doit être déployée.
        --init
        --no-init
            Forcer (resp. empêcher) la création des répertoires d'hôte correspondant
            aux hôtes spécifiés. Par défaut, la création des répertoires d'hôte est
            effectuée uniquement si ce script est lancé sans argument.
        --sysinfos
            Après un déploiement réussi sur l'hôte distant, inscrire si ce n'est
            déjà fait le résultat de la commande usysinfos dans le fichier
            sysinfos.conf du répertoire d'hôte.
            Cette option est automatiquement activée si ce script est lancé sans
            argument (hors options).
    }}}

    {{{
    ruinst: Déploiement distant avec uinst

    USAGE
        ruinst [-h host] [-T tmproot] <file|archive|dir> [-- options de uinst]

    note: à cause d'une limitation de makeself, les options de uinst ne devraient
    pas contenir d'espaces ni de caractères spéciaux. L'échappement de ces
    caractères n'est pas garanti.

    OPTIONS
        -C  Ne pas faire le déploiement. Configurer uniquement la connexion par clé
            sur les hôtes distants spécifiés pour le user spécifié. Il faut pouvoir
            se connecter par mot de passe pour configurer la connexion par clé.
            Si l'on veut configurer la connexion par clé pour le user root, mais que
            ce n'est pas possible de se connecter par mot de passe avec le user root
            sur l'hôte distant, et qu'il existe un user sudoer sur l'hôte distant,
            il est possible de faire la configuration avec '--configure root'. La
            commande serait alors
                ruinst -h user@host --configure root
            Si l'hôte distant n'a pas sudo ou si sudo n'est pas configuré, il faut
            rajouter l'option --uses-su, e.g:
                ruinst -h user@host --configure root --uses-su
        -T tmproot
            Spécifier le répertoire temporaire sur l'hôte distant, comme par exemple
            /var/tmp. Cette option est utile pour les vservers, qui ont par défaut
            un /tmp minuscule de 16 Mo.
        -S, --ssh ssh
            Spécifier le programme à utiliser pour la connection par ssh.
        -h hosts
        -h @hostsfile
            Spécifier un ou plusieurs hôtes sur lequels faire le déploiement. Pour
            spécifier plusieurs hôtes, il est possible d'utiliser plusieurs fois
            l'option -h, ou spécifier en une seule fois plusieurs hôtes en les
            séparant par un espace ou le caractère ':', e.g. 'host1 host2' ou
            'host1:host2'. Si la spécification contient les caractères { et },
            l'expansion est effectuée, e.g
                -h 'root@{host1,host2}.univ.run'
            Par défaut, la connexion sur l'hôte distant se fait avec l'utilisateur
            root. Il est possible de spécifier un autre utilisateur avec la syntaxe
            user@host, e.g -h user@host
            La forme @hostsfile permet de lire la liste des hôtes depuis le fichier
            hostsfile, à raison d'un hôte par ligne.
    }}}

    {{{
    rumount: démonter un système de fichier récursivement

    USAGE
        rumount mountpoint

    Démonter tous les systèmes de fichiers qui sont montés en-dessous de mountpoint
    puis démonter mountpoint. Démonter aussi tous les systèmes de fichiers
    bind-montés à partir d'un sous-répertoire de mountpoint.
    }}}

    {{{
    runs: Lancer un script avec le protocole runs

    USAGE
        runs [options] rscriptname name=value...
        runs [options] @recipe name=value...
        runs [options] -f rscript name=value...
        runs [options] -r recipe name=value...

    OPTIONS
    Configuration
        --init
        --verify
            Vérifier le nom d'hôte et créer si nécessaire le répertoire d'hôte
            correspondant à l'hôte courant ou à l'hôte spécifié avec l'option -h
            Avec --verify, la création du répertoire d'hôte n'est pas effectuée.
        --sysinfos DATA
            Avec l'option --init, initialiser le fichier sysinfos.conf avec DATA, si
            le fichier n'a pas déjà été provisionné. Sans cette option, un fichier
            vide avec des commentaires est créé à la place.
        --create RSCRIPT
            Créer un modèle de script avec le nom donné.
            Avec l'option -h, le script est créé dans le répertoire d'hôte
            correspondant à l'hôte spécifié

    Gestion des scripts
        -s  Forcer l'exécution du script avec l'utilisateur root si ce n'est pas
            déjà le cas
        -f RSCRIPT
            Lancer le script individuel spécifié au lieu de chercher dans les
            répertoires de $RUNSSCRIPTSPATH
        -r RECIPE
            Lancer les scripts spécifiés dans le fichier de recettes individuel
            spécifié.
        -h HOSTNAME[.DOMAIN]
            Spécifier que les scripts sont destinés à être lancés sur l'hôte
            spécifié. Les scripts sont alors aussi cherchés dans les répertoires
            {$RUNSHOSTSPATH}/$hostname.$domain (par défaut) et
            {$RUNSHOSTSPATH}/$domain/$hostname (le cas échéant)
            L'option --host est équivalente, sauf que son argument est facultatif et
            que sa valeur par défaut est l'hôte courant, soit sulfure
        --list
            Afficher la liste des scripts qui sont disponibles. Avec l'option -h,
            inclure aussi les scripts spécifiques à cet hôte.
            Avec cette option, les arguments supplémentaires agissent comme des
            filtres (regexp utilisée avec l'opérateur == de la commande [[). Les
            noms des scripts doivent valider au moins un filtre.
        --info
            Afficher la la description du script et la valeur de chaque variable
            définies
        --desc-only
            Afficher seulement la description du script
        -z  Forcer la réinstallation des scripts qui se basent sur shouldrun/setdone
    }}}

    {{{
    runsconfig: Gérer un répertoire d'hôte de runs

    USAGE
        runsconfig -c [host [destdir]]
        runsconfig -t -- args...

    OPTIONS
        -c, --create
            Créer un nouveau répertoire de configuration pour un hôte
        -d, --destdir DESTDIR[=runs]
            Nom du répertoire local de configuration.

        -t, --template [OPT]
            Gérer les fichiers du répertoire local avec templatectl. La valeur de
            cette option est utilisée comme argument court pour l'invocation de
            templatectl, e.g
                runsconfig -tm args
            est équivalent à
                templatectl -m args
            Les arguments qui restent sont passés tels quels à templatectl
            Les options courantes de templatectl -l, -v, -m, -L sont disponibles
            directement
        --help-template
            Afficher l'aide concernent la gestion des templates.
            Equivalent à -t -- --help
        -h, --host HOST
            Spécifier l'hôte. Equivalent à -v host=HOST
    }}}

    {{{
    runsmod: récupérer des dépôts git à usage de runs

    USAGE
        runsmod [options] [-h host] [modules...]

    Tous les dépôts spécifiés dans la configuration sont récupérés. Si des modules
    sont spécifiés, les dépôts correspondants sont récupérés aussi. Avec l'option
    -h, des dépôts spécifiques à l'hôte peuvent éventuellement être récupérés en
    plus.

    OPTIONS
        -c, --config CONFIG
            Spécifier un fichier de configuration à charger au lieu de la valeur par
            défaut ~/etc/default/runs
        --prod
        --devel
            Forcer un mode de sélection des urls. En mode production, préférer pour
            le clonage les urls de production, qui sont en principe accessibles sans
            authentification et en lecture seule. En mode développement, préférer
            pour le clonage les urls de développement, qui sont en principe
            accessibles par clé ssh et en lecture/écriture
        --no-fetch
            Ne rien récupérer. Utile avec --update-repolist
        -N, --no-host
        -A, --all-hosts
        -H, -h, --host HOST
        -T, --this-host
            Options permettant de spécifier l'hôte pour la récupération de dépôts
            spécifiques.
            --no-host demande explicitement à ce qu'aucun hôte ne soit spécifié
            --all-hosts sélectionne tous les dépôts spécifiques
            --host récupère uniquement les dépôts pour l'hôte spécifié
            --this-host équivaut à --host sulfure
            L'option par défaut est --this-host en mode production et --all-hosts en
            mode développement
        --update-repolist
            Forcer la mise à jour de la liste des dépôts. En principe, cette mise à
            jour n'est pas faite plus d'une fois par période de 24 heures.
        -0, --offline
        -n, --no-pull
        -u, --pull
            Spécifier le mode opératoire pour la récupération des dépôts.
            En mode --offline, ni clone ni pull ne sont autorisés. Le module doit
            avoir déjà été cloné.
            En mode --no-pull, seul le clonage est autorisé, e.g. le dépôt est
            cloné si ce n'est pas déjà le cas.
            En mode --pull, cloner le dépôt si ce n'est pas déjà le cas, ou le
            mettre à jour le dépôt avant de l'utiliser s'il avait déjà été cloné.
            Par défaut, utiliser --pull en mode production et --no-pull en mode
            développement.
        -i, --identity IDENTITY_FILE
            Spécifier le fichier depuis lequel lire la clé privée pour les
            connexions par ssh.
        -o, --output OUTPUT
            Spécifier un fichier dans lequel écrire des définitions de variables,
            notamment REPODIRS qui reçoit la liste des chemins des dépôts qui ont
            été récupérés. De plus, les variables RUNSSCRIPTSPATH, RUNSMODULESPATH
            et RUNSHOSTSPATH sont définies.
        -a, --append-output
            Ajouter au fichier OUTPUT au lieu de l'écraser
    }}}

    {{{
    rwoinst: Déploiement distant avec woinst

    USAGE
        rwoinst [-H host] [-T tmproot] <file|archive|dir>... [-- options de woinst]

    OPTIONS
        -C  Ne pas faire le déploiement. Configurer uniquement la connexion par clé
            sur les hôtes distants spécifiés pour le user spécifié. Il faut pouvoir
            se connecter par mot de passe pour configurer la connexion par clé.
            Si l'on veut configurer la connexion par clé pour le user root, mais que
            ce n'est pas possible de se connecter par mot de passe avec le user root
            sur l'hôte distant, et qu'il existe un user sudoer sur l'hôte distant,
            il est possible de faire la configuration avec '--configure root'. La
            commande serait alors
                rwoinst -H user@host --configure root
        -T tmproot
            Spécifier le répertoire temporaire sur l'hôte distant, comme par exemple
            /var/tmp. Cette option est utile pour les vservers, qui ont par défaut
            un /tmp minuscule de 16 Mo.
        -S ssh
            Spécifier le programme à utiliser pour la connection par ssh.
        -H host
            Spécifier un hôte distant sur lequel faire le déploiement. Plusieurs
            options -H peuvent être spécifiées, ou alors on peut séparer plusieurs
            hôtes par ':', e.g. -H host1:host2
            Par défaut, la connexion sur l'hôte distant se fait avec l'utilisateur
            root. Il est possible de spécifier un autre utilisateur avec la syntaxe
            user@host, e.g -H user@host
    }}}

    {{{
    USAGE:
        sqlcsv [query]

    query   est la requête SQL à exécuter. Si query n'est pas spécifiée ou si elle
            vaut '-', la requête SQL est lue sur l'entrée standard, ou depuis un
            fichier si l'option -f est spécifiée.

    DEMARRAGE

    Au démarrage, les répertoires de configuration (utilisateur ~/.sqlcsv et système
    /etc/sqlcsv) sont analysés. Les fichiers *.jar situés dans ces répertoires sont
    ajoutés au CLASSPATH. La présence de certains fichiers est testée pour activer
    éventuellement les logs détaillés.

    OPTIONS
        -C, --config CONFIG
            Prendre les informations de connexion depuis le fichier de propriété
            spécifié. Pour l'identifiant CONN, la propriété 'CONN.url' doit exister
            dans ce fichier avec la valeur de l'url jdbc de connexion. De plus, les
            propriétés 'CONN.user' et 'CONN.password' contiennent respectivement si
            nécessaire le nom et le mot de passe de connexion. La propriété
            'loglevel', si elle existe, est utilisée pour configurer le niveau
            d'affichage des logs, comme avec l'option --loglevel
            Si cette option n'est pas spécifiée, un fichier nommé sqlcsv.properties
            est recherché dans l'ordre: dans le répertoire courant, dans le
            répertoire de configuration utilisateur, puis dans le répertoire de
            configuration système. Si le fichier est trouvé, il est chargé
            automatiquement.
        -l, --conn CONN
            Spécifier l'identifiant (ou l'url) de connexion. Cette information est
            obligatoire. Si cette option n'est pas fournie, il faut spécifier un
            fichier de configuration avec l'option -C dans lequel *une seule*
            propriété 'CONN.url' est définie.
        -u, --user USER
        -p, --password PASSWORD
            Spécifier un nom de connexion et un mot de passe si l'url ne le fournit
            pas. Ces valeurs ont la priorité sur les valeurs éventuellement déjà
            présentes dans le fichier de propriété.
        -f, --input INPUT
            Lire la requête depuis le fichier INPUT au lieu de la lire depuis la
            ligne de commande ou l'entrée standard. Ne pas spécifier cette option ou
            utiliser '-' pour lire depuis l'entrée standard. Cette option est
            ignorée si la requête est fournie sur la ligne de commande.
        -o, --output OUTPUT
            Ecrire le résultat dans le fichier OUTPUT. Utiliser '-' pour spécifier
            la sortie standard (c'est la valeur par défaut). S'il y a plusieurs
            requêtes et que le fichier de sortie n'est pas la sortie standard,
            ajouter un numéro incrémental au nom du fichier en sortie pour chaque
            requête. Sinon, il est possible de spécifier plusieurs fois cette option
            pour nommer les fichiers correspondant à chaque requête.
        -t, --autocommit
            Activer le mode autocommit
        -c, --ignore-io-error
            Continuer le traitement même en cas d'erreur du système de fichiers.
            Cependant le traitement s'arrête et la transaction est annulée si une
            autre erreur se produit.
        -y, --ignore-any-error
            Continuer le traitement même en cas d'erreur quelconque.
        -n, --no-headers
            Ne JAMAIS inclure les en-têtes dans la sortie, même avec l'option -h
        -a, --append
            Ajouter le résultat au fichier OUTPUT au lieu de l'écraser.
        -A, --auto-na
            Activer les option -n -a si le fichier OUTPUT existe et qu'il est non
            vide. Le test n'est effectué que pour le premier fichier spécifié.
        -s, --same-output
            Utiliser le même fichier pour écrire le résultat de toutes les requêtes.
            Normalement, un numéro incrémental est ajouté au fichier en sortie si
            plusieurs requêtes sont spécifiées. Si les en-têtes sont les mêmes,
            ajouter le résultat au fichier directement à la suite. Sinon, sauter une
            ligne blanche et afficher les nouveaux en-têtes.
        -h, --force-headers
            En cas d'écriture du résultat de plusieurs requêtes dans un même
            fichier, ne pas tenter de concaténer les résultats même si les en-têtes
            sont les mêmes.
        --uc-output
            Ajouter dans la sortie les résultat de toutes les requêtes, pas
            seulement celles de type DQML
        --loglevel LOGLEVEL
            Spécifier le niveau de logs à afficher. Les valeurs valides sont à
            choisir parmi ALL, FINEST, FINER, FINE, CONFIG, INFO, WARNING, ERROR
            La présence de certains fichiers dans les répertoires de configuration
            utilisateur ou système configure les logs avant que les options de la
            ligne de commande ne soient analysés: un fichier DEBUG fait démarrer
            l'application avec le niveau de log ALL ce qui permet de voir les logs
            concernant le chargement des jar. Un fichier SQL_DEBUG permet d'activer
            la trace de DriverManager. Exemple:
                mkdir -p ~/.sqlcsv && touch ~/.sqlcsv/{DEBUG,SQL_DEBUG}
    }}}

    {{{
    twsync: synchroniser un répertoire de wiki avec un tiddlywiki

    USAGE
        twsync [options]

    Un répertoire de wiki est un répertoire où chaque page est contenu dans un
    fichier avec l'extension .twp
    Un tiddlywiki est un fichier html contenant le code de TiddlyWiki et les données
    associées.

    OPTIONS
        -d wikidir
        -f wikifile
            Spécifier le répertoire de wiki et le tiddlywiki à traiter. Par défaut,
            il s'agit de wiki.html dans le répertoire courant.
        -u  Importer les pages de wikidir dans le tiddlywiki. Utiliser cette action
            quand les pages de wikidir sont modifiées et qu'il faut mettre à jour le
            tiddlywiki.
            Il s'agit de l'action par défaut
        --force
            Forcer l'importation des pages même si les tiddlers correspondant sont
            plus récents dans le tiddlywiki
            Forcer aussi la regénération de wikifile même si aucune modification n'a
            été détectée
        -e  Exporter les tiddlers du tiddlywiki vers wikidir. Utiliser cette action
            quand le tiddlywiki a été modifié, et qu'il faut synchroniser wikidir
            avec les dernières modifications.
        -U  Mettre à jour le fichier wikifile avec la dernière version de tiddlywiki
            située dans ~/wop/modules/nutools/lib/tiddlywiki/empty.html
    }}}

    {{{
    uawk: wrapper pour des outils implémentés en awk

    USAGE
        uawk TOOL args...

    Les noms d'outils valides sont: awkrun awkcsv grepcsv awkfsv2csv mergecsv sortcsv dumpcsv printcsv
    Utiliser l'option --help pour obtenir de l'aide sur chacun des outils
    }}}

    {{{
    ubackup: faire une sauvegarde des fichiers

    USAGE
        ubackup [options]

    OPTIONS
        -l  Lister les profils de sauvegarde disponibles.
        -p  Spécifier le profil de sauvegarde à effectuer. Par défaut, toutes les
            sauvegardes sont effectuées.
        -u USER
            Faire le sauvegarde pour l'utilisateur $USER. Cette option n'est valide
            que pour l'utilisateur root.
        -n  Afficher ce qui doit être fait plutôt que de le faire
        -H  Arrêter la machine après une sauvegarde REUSSIE.
    }}}

    {{{
    ucalc: Afficher une valeur dans plusieurs unités

    USAGE
        ucalc value

    Sans suffixe, la valeur est exprimée en octets. Sinon, elle peut être suffixée
    pour spécifier l'unité dans laquelle est exprimée la valeur:
        K,M,G,T -- Kibi (1024), Mibi (1024^2), Gibi (1024^3), Tebi (1024^4)
        k,m,g,t -- Kilo (1000), Mega (1000^2), Giga (1000^3), Tera (1000^4)
        s       -- secteurs de 512 octets
        S       -- secteurs de 2048 octets
        p       -- pages de 4096 octets
        c       -- cylindres (si l'option -c est spécifiée)
        b       -- octets

    OPTIONS
        -u UNIT
            Spécifier l'unité de value. Le suffixe qui est éventuellement sur value
            est ignoré.
        -o UNIT
            Spécifier l'unité en sortie. Par défaut, afficher la valeur dans toutes
            les unités supportées.
        -c VALUE
            Taille d'un cylindre en octets, pour permettre l'affichage des valeurs
            en cylindres
    }}}

    {{{
    uconf: Activer ou désactiver un paramètre dans un fichier de configuration

    USAGE
        uconf [options] config name[=value]...

    OPTIONS
        -e
            Activer le paramètre (par défaut). Si le paramètre existe, mais est
            commenté, il est décommenté. Si une valeur est spécifiée pour le
            paramètre, le paramètre est modifié dans le fichier en conséquence.
        -q
            Cette option s'utilise avec l'option -e et le type shell. Elle permet
            de s'assurer que les valeurs ayant des espaces et/ou des caractères
            spéciaux sont quotées
        -d
            Désactiver le paramètre. Le paramètre est commenté s'il existe dans le
            fichier
        -a
            Ajouter une valeur à la variable, ou un paramètre avec cette valeur
            (suivant le type de fichier de configuration)
        -A
            Ajouter une valeur au tableau, ou un paramètre avec cette valeur
            (suivant le type de fichier de configuration)
        -t TYPE
            Type de fichier de configuration. TYPE peut être sh (par défaut), apache
            ou mysql.
            shell
                les paramètres sont de la forme 'name=value', et les commentaires
                débutent par '#'. Ce type peut être utilisé pour tous les fichiers
                ayant ces caractéristiques, dont les fichiers de script shell
            apache
                les paramètres sont de la forme 'name value', et les commentaires
                débutent par '#'. Ce type peut être utilisé pour tous les fichiers
                ayant ces caractéristiques, dont les fichiers de configuration
                apache
            mysql, php
                les paramètres sont dans des sections nommées de la forme [section],
                sont de la forme 'name=value', et les commentaires débutent par '#'
                ou ';'
                Ce type peut être utilisé pour tous les fichiers ayant ces
                caractéristiques, dont les fichiers de configuration de mysql et de
                php. Avec ce type, la section est obligatoire.
        -s SECTION
            Avec le type mysql, préciser la section dans laquelle inscrire le
            paramètre. Attention! La section DOIT exister, elle n'est pas créée
            automatiquement.
    }}}

    {{{
    ucrontab: Ajouter/Supprimer une ligne dans crontab

    USAGE
        ucrontab [options] ctline

    OPTIONS
        -a  Ajouter la ligne dans le fichier crontab (par défaut)
        -r  Enlever la ligne dans le fichier crontab
        -u user
            Spécifier l'utilisateur pour lequel on modifie crontab. Par défaut,
            modifier le crontab de root
        -H host:hosts...
            Modifier le crontab sur les hôtes distants spécifiés. Avec l'hôte '.' ou
            'localhost', la modification est faite sur l'hôte local
            Si l'action est -a, un script 'undo-ucrontab.sh' est créé dans le
            répertoire courant, qui annule la planification. Il est possible de
            lancer ce script le lendemain pour enlever les planifications
            installées.
        ctline
            Ligne de crontab de la forme 'minutes hours days months dows command'
            Si la ligne est de la forme halt[@hh:mm], la commande 'shutdown -h now'
            est planifiée pour le LENDEMAIN à hh:mm. si hh:mm n'est pas spécifié,
            l'arrêt est planifié pour 7:00
        -t hh:mm
            Ignorer la partie 'minutes hours days months dows' de ctline, et la
            remplacer par une planification à hh:mm le LENDEMAIN.
        --dom dayOfMonth
        --month month
            Spécifier respectivement le jour du mois et le mois (1-12) auquel faire
            la planification. Par défaut, les planifications sont effectuées pour le
            LENDEMAIN. Il est conseillé de spécifier les deux arguments si le jour
            doit être fixé.
        -s cmdfile
            Spécifier un fichier, dont le contenu est utilisé pour générer le script
            qui est planifié. Le fichier doit contenir l'ensemble des commandes à
            exécuter. Le script est modifié pour s'autodétruire à la fin de son
            exécution. Si ce comportement n'est pas souhaité, il faut rajouter la
            commande 'exit 0' à la fin.
        -S cmd
            Comme -s, mais spécifier le contenu du fichier directement sur la ligne
            de commande.
        -f hostsfile
            Spécifier un fichier qui contient la liste des hôtes sur lesquels faire
            les planifications.
            Les options -s, -S, -H, -d, -n sont ignorées. L'option --add est valide
            jusqu'au premier @group du fichier. Voici le format de ce fichier:

            Un groupe d'hôte débute par une ligne de la forme '@group:adelay:gdelay'
            - adelay est le nombre de minutes à laisser passer entre les hôtes du
              groupe (par défaut 1)
            - gdelay est le nombre de minutes à laisser passer après le traitement
              du groupe (par défaut 15)
            Les autres lignes sont des hôtes sur lequels planifier l'opération, de
            la forme 'host:cmd'
            - host est un nom d'hôte pleinement qualifié, sur lequel il est possible
              de se connecter par clé.
            - cmd est une description de la commande à lancer pour effectuer
              l'opération planifiée. Utiliser la syntaxe '<script' pour prendre le
              contenu du fichier de script spécifié. Le script est copié dans un
              fichier temporaire sur l'hôte, et se supprime après son
              lancement. Sinon, la commande spécifiée est utilisée telle quelle. Si
              cmd n'est pas spécifié, prendre la commande par défaut donnée par
              ctline
            Les lignes vides et commençant par '#' sont ignorées
            La commande '@include:file' permet d'inclure un autre fichier

        -d  Activer l'incrémentation automatique des heures de planification entre
            chaque hôte. Ceci permet par exemple de planifier l'arrêt d'un certain
            nombre de machines dans un ordre précis, en horaire décalé.
            Cette option est activée par défaut si ctline==halt[@time]
        -n  Désactiver l'incrémentation automatique des heures de planification.
        --add ADELAY
            Spécifier le nombre de minutes entre chaque hôte pour l'incrémentation
            automatique des heures de planification. Par défaut, il y a 1 minute
            entre chaque hôte.
        --us undo-script
            Spécifier le nom du script qui annule la planification. Utiliser ""
            pour désactiver cette fonctionnalité.
        --fake
            Afficher simplement les modifications qui doivent être effectuées.
    }}}

    {{{
    udaemon.cgo: start a program as a daemon

    USAGE
        udaemon.cgo /path/to/prog [args...]

    OPTIONS
        -d DESTDIR
            Change to DESTDIR instead of "/" before starting the program
    }}}

    {{{
    udir: gérer les variables de répertoire

    USAGE
        udir [options] [dir [name=value...]]

    Par défaut, mettre à jour les variables du répertoire avec les définitions
    données. Attention! Les définitions sont insérées *telles quelles* dans le
    fichier. Par exemple, pour définir une variable qui contient des espaces,
    on pourra faire:
        udir /path/to/dir 'var="value with spaces"'
    pour définir un tableau:
        udir /path/to/dir 'array=(first second)'

    OPTIONS
        -i, --show-desc
        -n, --show-note
            Afficher la description du répertoire. C'est l'action par défaut si ce
            script est lancé *sans argument*
        -d, --dump
            Afficher toutes les variables définies pour le répertoire 'dir'.
        -x, --eval 'CMDS;...'
            Exécuter les commandes dans le contexte des variables définies pour le
            répertoire.
        -e, --edit
            Editer les variables du répertoire
        --local-vars
            Avec -d, ajouter des directives 'local' aux définitions de variables
        -A, --all-parents
            Avec -d et -x, considérer les variables de tous les répertoires parents
            jusqu'à la racine. Pour ne considérer que les variables du répertoire
            spécifié (par défaut), utiliser --local-only
        --help-vars
            Afficher une descriptions des variables spécifiques aux outils de nutools
    }}}

    {{{
    udist: gestion d'une distribution upstream

    Des fichiers de configuration (par exemple) sont distribués par un partenaire,
    et il faut maintenir des modifications locales, tout en acceptant les mises à
    jour provenant de l'upstream. Ce script aide à maintenir un tel scénario.

    En général, la distribution upstream identifie les fichiers modifiables en leur
    donnant une extension particulière, par exemple 'file.origine' ou 'file.default'
    La liste des extensions reconnues est spécifiée avec l'option -s. Lors de leur
    intégration dans le répertoire local, ces fichiers sont copiés sans cette
    extension.

    Terminologie: Les fichiers pour lesquels il faut maintenir une version locale
    sont appelés 'fichiers locaux', qu'ils viennent de la distribution upstream ou
    non. Les autres fichiers qui proviennent de la distribution sont appelés
    'fichiers upstream'.

    USAGE
        udist cmd [options]

    OPTIONS COMMUNES
        -s .EXT
            Ajouter une extension à la liste des extensions reconnues comme contenu
            original modifiable dans la distribution upstream. Par défaut, les
            extensions suivantes sont reconnues:
                .udist .origine .default
            Cette option peut être utilisée autant de fois que nécessaire.
        --clear-origexts
            Supprimer la liste par défaut des extensions origines. Cette option doit
            être spécifiée avant l'option -s pour construire une nouvelle liste.
            La liste des extensions ne doit pas être vide. Si c'est le cas, elle est
            modifiée pour contenir l'unique élément (.udist)
        -d WORKDIR
            Spécifier le répertoire de travail. Par défaut, la racine du répertoire
            de travail est cherchée à partir du répertoire courant.
        --help
            Afficher l'aide détaillée de la commande spécifiée

    COMMANDES
        init [WORKDIR [ARCHIVE]]
            Initialiser un répertoire de travail pour contenir une distribution
            upstream

        upstream-new, new SRCDIR|ARCHIVE [WORKDIR]
            Intégrer une nouvelle distribution upstream.
            Les nouveaux fichiers sont copiés tout de suite dans le répertoire de
            travail. Par contre, les modifications ne sont intégrées qu'avec la
            commande patch
        upstream-clear, clear [WORKDIR]
            Supprimer tous les fichiers non modifiés de l'upstream.

        local-create, create FILE
            Créer et/ou identifier FILE comme une modification locale par rapport à
            l'upstream.
        local-edit, edit FILE
            S'assurer que local-create a été exécuté si nécessaire pour FILE, puis
            l'éditer avec vim

        local-copy, cp SRCFILE DESTFILE
        local-move, mv SRCFILE DESTFILE
        local-remove, rm FILE
            Frontend pour respectivement cp, mv et rm. Ces commandes agissent aussi
            sur les fichiers orig et de tag.

        local-tag, tag FILE TAG
            Faire une copie du fichier local avec le tag spécifié. Si le fichier de
            tag existe déjà, il est écrasé.
        local-switch, switch TAG FILE
            Sélectionner la copie avec le tag spécifié.

        local-put, put [WORKDIR] DESTDIR
            Copier tous les fichiers locaux dans DESTDIR, par exemple pour faire une
            sauvegarde. Si DESTDIR n'est pas spécifié, prendre la valeur de
            l'origine, affichée par local-list
        local-get, get [-l|-s] SRCDIR [WORKDIR]
            Opération inverse de local-put: intégrer tous les fichiers de SRCDIR
            comme fichiers locaux. Si SRCDIR n'est pas spécifié, prendre la valeur
            de l'origine, affichée par local-list
        local-list, list [WORKDIR]
            Lister tous les fichiers locaux. Les fichiers pour lesquels il faut
            intégrer une modification de l'upstream avec la commande local-patch
            sont identifiés visuellement.

        upstream-diff, udiff [FILE]
            Après intégration d'une nouvelle distribution upstream, afficher les
            modifications entre la nouvelle distribution upstream et l'ancienne pour
            tous les fichiers modifiables
        local-diff, ldiff [FILE]
            Afficher les modifications locales par rapport à l'upstream pour le(s)
            fichier(s) spécifié(s).
        local-patch, lpatch [FILE]
            Après intégration d'une nouvelle distribution upstream, appliquer au(x)
            le(s) fichier(s) spécifié(s) les modifications disponibles affichées par
            upstream-diff.
        local-forget, lforget [FILE]
            Après intégration d'une nouvelle distribution upstream, oublier les
            modifications disponibles pour le(s) fichier(s) spécifié(s).
    }}}

    {{{
    uenv: Mettre à jour la configuration de l'environnement

    USAGE
        uenv [-u [projdirs...]]

    Cette commande met à jour l'ordre de chargement des fichiers de configuration
    dans ~/etc/{profile.d,bashrc.d}. Elle est donc utile si ces fichiers ont été
    modifiés manuellement, ou si un fichier a été ajouté manuellement.

    OPTIONS
        HOME=/path/to/homedir
            Spécifier le chemin vers ~
            Cette option doit être placée avant les valeurs projdirs.
        -u, --update
            Installer ou mettre à jour les fichiers de profil des projets spécifiés:
            Les fichiers ~/.profile, ~/.bash_profile et ~/.bashrc sont vérifiés et
            corriger automatiquement pour inclure les fichiers de nutools.
            Ensuite, les fichiers de profil sont copié dans les répertoires
            ~/etc/{profile.d,bashrc.d,default}
            Les projets spécifiés *doivent* être configurés avec uinst -C, et
            définir la valeur install_profiles=true dans leur fichier .udir
            Si aucun projet n'est spécifié, prendre les fichiers de profil de
            nutools.
        -l, --local-profiles
            Avec l'option -u, installer les profils locaux comme tels. Pour les
            fichiers de profil qui sont indiqués comme non partagés, les copier dans
            des répertoires spécifiques de la forme {profile,bashrc}.HOSTNAME.d et
            default.HOSTNAME
        -s, --shared-profiles
            Installer les profils locaux comme des profils partagés. C'est l'option
            par défaut.
    }}}

    {{{
    ufixmod: forcer le mode d'une liste de fichiers

    USAGE
        ufixmod [options] [dirs|files....]

    Le mode forcé pour les répertoires est rwxr-xr-x
    Le mode forcé pour les fichiers est rw-r--r--

    OPTIONS
        -x, --executable
            Forcer le mode rwX-r-Xr-X pour les fichiers
    }}}

    {{{
    ugenpass: générer un mot de passe au hasard

    USAGE
        ugenpass [options]

    OPTIONS
        -l, --len LEN
            Spécifier le nombre de caractères du mot de passe généré
        -U, --upper COUNT
        -L, --lower COUNT
        -A, --alpha COUNT
        -N, --number COUNT
        -S, --symbol COUNT
        -B, --special COUNT
            Spécifier le nombre minimum de chaque classe de caractère
    }}}

    {{{
    uinc.py: Plier/déplier des inclusions dans un fichier

    USAGE
        uinc.py [[options] dest...]

    OPTIONS
        -f  Plier les inclusions
        -u  Déplier les inclusions (par défaut)
        -@  Forcer le caractère '@' pour le pliage/dépliage
        -*  Forcer le caractère '*' pour le pliage/dépliage
        --auto
            Activer la recherche automatique de paramètres (par défaut)
        --noauto
            Désactiver la recherche automatique de paramètres
        -I SPEC
            Spécifier des fichiers à inclure dans les répertoires spécifiés
        -X SPEC
            Spécifier des fichiers à exclure dans les répertoires spécifiés
        --refdir REFDIR
            Spécifier le répertoire de référence. Soit un répertoire DEST spécifié
            dans les arguments. Si un fichier à inclure *n'est pas* un fils du
            répertoire DEST, l'emplacement effectif du fichier est calculé en
            faisant comme si DEST==REFDIR.
            Par exemple, soit DEST=/dest/path et REFDIR=/refdir/path. Si le fichier
            /dest/path/file inclue le fichier ../inc, alors c'est le fichier
            /refdir/inc qui est considéré.
            Ceci permet de traiter les inclusions dans une copie temporaire d'un
            répertoire, dans le cas où les fichier font référence à d'autres
            fichiers situés relativement à l'emplacement original.

    Les spécifications de fichiers sont de types glob: ils peuvent contenir les
    wildcards * et ?. Ils supportent en plus la chaine '**' qui signifie n'importe
    quelle profondeur de répertoire. 'dir/' est équivalent à 'dir/**' et signifie
    tous les fichiers situés dans l'arborescence à partir de dir.

    La variable UINCPATH contient une liste de répertoires qui sont consultés pour
    trouver les fichiers à inclure.
    }}}

    {{{
    uinc.py: Plier/déplier des inclusions dans un fichier

    USAGE
        uinc.py [[options] dest...]

    OPTIONS
        -f  Plier les inclusions
        -u  Déplier les inclusions (par défaut)
        -@  Forcer le caractère '@' pour le pliage/dépliage
        -*  Forcer le caractère '*' pour le pliage/dépliage
        --auto
            Activer la recherche automatique de paramètres (par défaut)
        --noauto
            Désactiver la recherche automatique de paramètres
        -I SPEC
            Spécifier des fichiers à inclure dans les répertoires spécifiés
        -X SPEC
            Spécifier des fichiers à exclure dans les répertoires spécifiés
        --refdir REFDIR
            Spécifier le répertoire de référence. Soit un répertoire DEST spécifié
            dans les arguments. Si un fichier à inclure *n'est pas* un fils du
            répertoire DEST, l'emplacement effectif du fichier est calculé en
            faisant comme si DEST==REFDIR.
            Par exemple, soit DEST=/dest/path et REFDIR=/refdir/path. Si le fichier
            /dest/path/file inclue le fichier ../inc, alors c'est le fichier
            /refdir/inc qui est considéré.
            Ceci permet de traiter les inclusions dans une copie temporaire d'un
            répertoire, dans le cas où les fichier font référence à d'autres
            fichiers situés relativement à l'emplacement original.

    Les spécifications de fichiers sont de types glob: ils peuvent contenir les
    wildcards * et ?. Ils supportent en plus la chaine '**' qui signifie n'importe
    quelle profondeur de répertoire. 'dir/' est équivalent à 'dir/**' et signifie
    tous les fichiers situés dans l'arborescence à partir de dir.

    La variable UINCPATH contient une liste de répertoires qui sont consultés pour
    trouver les fichiers à inclure.
    }}}

    {{{
    uinst.sh: Déployer en local un fichier, une archive, ou un répertoire

    USAGE
        uinst.sh [options] <file|archive|dir>

    OPTIONS
        var=value
            Spécifier la valeur d'une variable ou d'un préfixe, plutôt que de
            laisser uprefix l'autodétecter. Utiliser 'uprefix -l' pour avoir une
            liste de préfixes valides. Utiliser 'udir --help-vars' pour avoir une
            liste de variables valides pour uinst.sh.
        -d /path/to/destdir
            Spécifier le répertoire destination, exactement comme si la valeur
            destdir avait été spécifiée, i.e destdir="/path/to/destdir"
        -h, --host [user@]host
            Avec la méthode de déploiement uinst:rsync, permettre de spécifier un
            hôte différent. Cette option est ignorée pour les autres méthodes de
            déploiement. Si host vaut localhost, un déploiement local avec ssh est
            effectué. Si host vaut '.', un déploiement local *sans passer par ssh*
            est effectué, comme si seul le chemin avait été spécifié.
            Cette option initialise la valeur destdir_override_userhost
        -S, --ssh ssh
            Avec la méthode de déploiement uinst:rsync, spécifier le programme à
            utiliser pour la connection par ssh. Cette option initialise la valeur
            destdir_ssh
        --force-remote
            Avec la méthode de déploiement uinst:rsync, si un hôte est spécifié dans
            la valeur de destdir, forcer le déploiement distant avec ssh+rsync, même
            si l'hôte et l'utilisateur correspondent aux valeurs courantes. Cette
            option initialise la valeur destdir_force_remote
        -a, --auto
            Si la source n'est pas spécifiée, déterminer le répertoire à déployer
            automatiquement (c'est la valeur par défaut)
        --no-auto
            Ne pas déterminer automatiquement le répertoire à déployer.
        --prefix
            Corriger les chemins srcdir et destdir qui commencent par des préfixes
            valides (c'est la valeur par défaut). Utiliser 'uprefix -l' pour avoir
            une liste de préfixes valides
        --no-prefix
            Ne jamais corriger un chemin.
        --include-vcs
            Inclure les fichiers de VCS dans les fichiers copiés. Par défaut, les
            fichiers de VCS sont exclus.
        -l, --local-profiles
            Installer les profils locaux comme tels
        --shared-profiles
            Installer les profils locaux comme des profils partagés. C'est la valeur
            par défaut pour compatibilité.
        -C  Configurer un répertoire pour le déploiement avec uinst
            Ajouter l'option --force pour forcer la reconfiguration
    }}}

    {{{
    uinst: Déployer en local un fichier, une archive, ou un répertoire

    USAGE
        uinst [options] <file|archive|dir>

    OPTIONS
        var=value
            Spécifier la valeur d'une variable ou d'un préfixe, plutôt que de
            laisser uprefix l'autodétecter. Utiliser 'uprefix -l' pour avoir une
            liste de préfixes valides. Utiliser 'udir --help-vars' pour avoir une
            liste de variables valides pour uinst.
        -d /path/to/destdir
            Spécifier le répertoire destination, exactement comme si la valeur
            destdir avait été spécifiée, i.e destdir="/path/to/destdir"
        -h, --host [user@]host
            Avec la méthode de déploiement uinst:rsync, permettre de spécifier un
            hôte différent. Cette option est ignorée pour les autres méthodes de
            déploiement. Si host vaut localhost, un déploiement local avec ssh est
            effectué. Si host vaut '.', un déploiement local *sans passer par ssh*
            est effectué, comme si seul le chemin avait été spécifié.
            Cette option initialise la valeur destdir_override_userhost
        -S, --ssh ssh
            Avec la méthode de déploiement uinst:rsync, spécifier le programme à
            utiliser pour la connection par ssh. Cette option initialise la valeur
            destdir_ssh
        --force-remote
            Avec la méthode de déploiement uinst:rsync, si un hôte est spécifié dans
            la valeur de destdir, forcer le déploiement distant avec ssh+rsync, même
            si l'hôte et l'utilisateur correspondent aux valeurs courantes. Cette
            option initialise la valeur destdir_force_remote
        -a, --auto
            Si la source n'est pas spécifiée, déterminer le répertoire à déployer
            automatiquement (c'est la valeur par défaut)
        --no-auto
            Ne pas déterminer automatiquement le répertoire à déployer.
        --prefix
            Corriger les chemins srcdir et destdir qui commencent par des préfixes
            valides (c'est la valeur par défaut). Utiliser 'uprefix -l' pour avoir
            une liste de préfixes valides
        --no-prefix
            Ne jamais corriger un chemin.
        --include-vcs
            Inclure les fichiers de VCS dans les fichiers copiés. Par défaut, les
            fichiers de VCS sont exclus.
        -l, --local-profiles
            Installer les profils locaux comme tels
        --shared-profiles
            Installer les profils locaux comme des profils partagés. C'est la valeur
            par défaut pour compatibilité.
        -C  Configurer un répertoire pour le déploiement avec uinst
            Ajouter l'option --force pour forcer la reconfiguration
    }}}

    {{{
    ujava: Lancer un script après avoir sélectionné une version de java

    USAGE
        ujava [options] version [args...]

    OPTIONS
        -b, --bits 32|64|auto
        --32
        --64
            Sélectionner une version 32 ou 64 bits de java
        -e, --exact
            Sélectionner la version *exacte* de java demandée, au lieu de la version
            minimum correspondant à la version demandée.
            Si la version requise de java n'est pas trouvée, retourner avec le code
            d'erreur 254.

    La version de java attendue peut-être exprimée de l'une des façons suivantes:
    1.4 1.4+ 1.5 1.5+ 1.6 1.6+ 1.7 1.7+
    Si args n'est pas spécifié, un shell est lancé dans lequel les variables
    JAVA_HOME, JAVA, JAVAC et PATH sont mis à jour.
    }}}

    {{{
    uldap: Shell pour accéder à un serveur ldap

    USAGE
        uldap [options]

    OPTIONS
        -C profile
            Sélectionner un profil de connexion. Par défaut, si l'option -H n'est
            pas spécifiée, le premier profil est sélectionné.
        -x  Ne pas tenter de faire une connexion sur le profil par défaut si aucun
            profil n'est sélectionné.
        -f script
            Lire les commandes depuis le script spécifié.
        -n  Avec un script donné en ligne de commande ou lu depuis un fichier, ne pas
            ajouter automatiquement la commande print à la fin
        -i  Si un script est spécifié, passer en mode interactif après l'exécution
            du script.
        -e  Forcer l'arrêt du script si une erreur se produit. C'est l'option par
            défaut pour un script spécifié avec -f.
        -l input.ldif
            Charger le fichier input.ldif comme espace de travail initial
        -H ldapuri
        -D binddn
        -w password
        -b searchbase
        -v var=value

    COMMANDES
        $ cmd
            Passer directement une commande au shell.
        set [options] [var=value...]
            Changer des options ou des variables. set sans argument affiche la liste
            des variables définies.
        [set] plain
            Passer en mode 'plain': indiquer que l'espace de travail contient des
            données brutes. Les pré-traitements et post-traitements (uncut_on_load,
            decode_on_load, encode_on_save, cut_on_save) ne sont pas appliqués sur
            cet espace de travail
        [set] ldif
            Passer en mode 'ldif': indiquer que l'espace de travail contient des
            données ldif. Les pré-traitements et post-traitements sont appliqués
            normalement sur cet espace de travail
        [set] append
            Pour certaines opérations, spécifier si le résultat de la *prochaine*
            opération remplace le contenu de l'espace de travail courant (par
            défaut), ou si le résultat est ajouté à la fin.
        last
            Afficher en mode édition la dernière commande. Cette commande n'est
            fonctionnelle qu'avec une version de bash >=4.x
        profile name
            Choisir le profil 'name'. Equivalent à 'set profile=name'. Sans
            argument, afficher la liste des profils valides.
        auth anonymous|binddn [password]
            Spécifier le compte à utiliser pour se connecter. Equivalent à
            'set binddn=binddn; set password=password'
        clear [-k]
            Vider l'espace de travail et passer en mode 'plain'.
            Avec l'option -k, supprimer aussi tout l'historique d'annulation.
        load [-k] input
            Charger un fichier dans l'espace de travail. Si l'extension du fichier
            est .ldif, passer en mode 'ldif'
            En mode append, rajouter le contenu du fichier à l'espace de travail,
            puis repasser en mode replace.
            Le code de retour est 0 si le fichier a été chargé, 1 sinon.
        save [-a] output
            Sauvegarder l'espace de travail dans un fichier.
            Avec l'option -a, rajouter au fichier au lieu de l'écraser
        print
            Afficher l'espace de travail
        alias a=rdn...
            Définir un alias pour la commande cd. 'a' est l'alias, 'rdn' est le dn
            correspondant, exprimé par rapport à $suffix. Sans argument, afficher
            la liste des aliases définis.
        cd rdn
            Changer searchbase. Par défaut, il s'agit d'un rdn relatif à $searchbase
            - Certains aliases sont supportés: .. pour l'objet parent, ~ pour
              $suffix, / pour la racine. 'cd' sans argument équivaut à 'cd ~'
            - Si le dn commence par '~/', il s'agit d'un rdn relatif à $suffix.
            - Si le dn commence par /, searchbase reçoit la valeur rdn sans
              modifications (sauf bien sûr enlever le '/' de tête si nécessaire). Il
              faut alors que ce soit un dn absolu.
        ls [-b searchbase] [filter [attrs...]]
        search [-b searchbase] [filter [attrs...]]
            Utiliser ldapsearch pour faire la recherche, et copier le résultat dans
            l'espace de travail. 'ls' est équivalent à 'search -s one'. Si ce n'est
            pas déjà le cas, passer en mode 'ldif'.
            L'option -b prend une valeur avec la même syntaxe que la commande cd,
            sauf que les alias ne sont pas supportés. En particulier, la valeur est
            relative au $searchbase courant. Pour faire une recherche par rapport à
            $suffix, il faut utiliser la syntaxe ~/searchbase.
            En mode append, rajouter le résultat de la recherche à l'espace de
            travail, puis repasser en mode replace.
            Le code de retour est 1 si aucun enregistrement n'a été trouvé, sinon
            le code de retour est celui de la commande ldapsearch.
        cut Couper les lignes trop longues. Cette action est en principe effectuée
            automatiquement lors de la sauvegarde. Il n'est pas conseillé
            d'appliquer des méthodes de transformation après avoir utilisé cette
            action.
        uncut
            Fusionner les lignes coupées. Cette action est en principe effectuée
            automatiquement lors du chargement ou après la recherche.
        encode [attrs...]
            Encoder en base64 les valeurs des attributs mentionnés.
        decode [attrs...]
            Décoder les valeurs des attributs mentionnés si nécessaire (c'est à dire
            s'ils sont encodés en base64)
        keepattr attrs...
            Garder uniquement les lignes des attributs mentionnés. Ensuite,
            supprimer les objets ayant uniquement la ligne dn: (en d'autres termes,
            keepattr sans argument supprime *tout* l'espace de travail)
        keepval attr patterns...
            Pour l'attribut attr, garder uniquement les lignes pour lesquelles les
            valeurs correspondent aux expressions régulières. Les autres attributs
            ne sont pas modifiés. Ensuite, supprimer les objets ayant uniquement la
            ligne dn:
        exclude attrs...
            Supprimer les lignes des attributs mentionnés. Ensuite, supprimer les
            objets ayant uniquement la ligne dn:
        excludeval attr patterns...
            Pour l'attribut attr, supprimer les lignes pour lesquelles les
            valeurs correspondent aux expressions régulières. Les autres attributs
            ne sont pas modifiés. Ensuite, supprimer les objets ayant uniquement la
            ligne dn:
        keepvalentry attr patterns...
            Pour l'attribut attr, vérifier si *au moins une* valeur correspond à
            l'une des expressions régulières. Si c'est le cas, garder l'entrée
            entière, sinon supprimer l'entrée.
        excludevalentry attr patterns...
            Pour l'attribut attr, vérifier si *aucune* des valeurs ne correspond à
            l'une des expressions régulières. Si c'est le cas, garder l'entrée
            entière, sinon supprimer l'entrée.
        setval attr values...
            Remplacer toutes les valeurs de l'attribut attr par les valeurs
            spécifiées.
        addval attr values...
            Ajouter un nouvel attribut avec les valeurs spécifiées. Si l'attribut
            existe déjà, les nouvelles valeurs sont ajoutées à la fin.
        sed args
            Modifier l'espace de travail avec le résultat de la commande sed.
            note: aucun argument n'est filtré, mais il ne faut pas utiliser les
            options de sed qui provoquent la modification en place du fichier,
            comme par exemple l'option -i
        awk args
            Modifier l'espace de travail avec le résultat de la commande awk.
        grep args
            Modifier l'espace de travail avec le résultat de la commande grep.
        format [options] attrs...
            Formater l'espace de travail en données tabulaires, et passer en mode
            'plain'.
            --show-headers
                Afficher les en-têtes
            -F FSEP
                Spécifier le séparateur pour les attributs. Par défaut, il s'agit du
                caractère de tabulation.
            -R VSEP
                Spécifier le séparateur pour les valeurs des attributs. Par défaut, il
                s'agit du point-virgule ';'
            -e  Retourner les valeurs comme des variables shell. Les options -F et -R
                sont ignorées. Les attributs multivalués sont écrits sous forme de
                tableaux. Par exemple:
                    attributes=('mail' 'givenName')
                    index=0
                    mail='user@domain.fr'
                    givenName=('peter' 'gabriel')
            --bc
                Dans le mode -e, spécifier une commande à insérer avant le premier
                enregistrement. Quand cette commande est lancée, index==-1
            -c  Dans le mode -e, spécifier une commande à insérer après chaque
                enregistrement
            --ec
                Dans le mode -e, spécifier une commande à insérer après le dernier
                enregistrement
        sort [args]
            Modifier l'espace de travail avec le résultat de la commande sort.
        edit
            Lancer un éditeur pour modifier l'espace de travail.
        diff [options]
            Afficher les différences entre l'espace de travail et la version
            précédente
        ifok cmd
        iferror cmd
            Si le dernier code de retour est 0 (resp. !=0), lancer la commande cmd
        skip n
            Sauter les n prochaines commandes. A utiliser avec ifok et iferror
        undo
            Annuler la dernière modification effectuée sur l'espace de travail

    Les directives suivantes prennent le contenu de l'espace de travail, et le
    transforment en une suite de commandes de modifications pour ldapmodify:

        A   Créer un objet de toutes pièces avec les attributs donnés et leurs
            valeurs.
        a   Ajouter les valeurs spécifiée à l'attribut
        r   Remplacer les valeurs de l'attribut par celles spécifiées
        d   Supprimer les valeurs spécifiées de l'attribut
        D   Supprimer l'attribut
        delentry
            Supprimer l'objet
        ldapmodify
            Utiliser ldapmodify pour modifier les objets sur le serveur. Il faut
            utiliser au préalable l'une des méthodes de transformation parmi A, a,
            r, d, D, delentry.
            Le code de retour est celui de la commande ldapmodify.
        ldapadd
            Utiliser ldapadd pour créer les objets situés dans l'espace de travail.
            Le code de retour est celui de la commande ldapadd.
        ldapdelete
            Utiliser ldapdelete pour supprimer la liste des dns situés dans l'espace
            de travail.
            Le code de retour est celui de la commande ldapdelete.

    Notes:
    - les expressions régulières sont celles reconnues par awk.
    - pour spécifier plusieurs actions sur une même ligne, les séparer par //
    - le code de retour est 0 si ok, 255 si une erreur s'est produite (erreur de
      syntaxe, de connexion, de lecture/écriture de fichier, etc.). sinon, les
      opérations ldap{search,modify,delete,add} ont leur code de retour respectifs
    }}}

    !Liste des librairies de ulib
    * [[ulib/apache]]
    * [[ulib/apache.tools]]
    * [[ulib/auto]]
    * [[ulib/awk]]
    * [[ulib/base]]
    * [[ulib/base.args]]
    * [[ulib/base.array]]
    * [[ulib/base.bool]]
    * [[ulib/base.compat]]
    * [[ulib/base.core]]
    * [[ulib/base.init]]
    * [[ulib/base.num]]
    * [[ulib/base.quote]]
    * [[ulib/base.split]]
    * [[ulib/base.string]]
    * [[ulib/base.tools]]
    * [[ulib/base.ulib]]
    * [[ulib/bash]]
    * [[ulib/cgi]]
    * [[ulib/cgisupport]]
    * [[ulib/compat]]
    * [[ulib/conf]]
    * [[ulib/crontab]]
    * [[ulib/debian]]
    * [[ulib/DEFAULTS]]
    * [[ulib/install]]
    * [[ulib/ipcalc]]
    * [[ulib/java]]
    * [[ulib/javaproperties]]
    * [[ulib/json]]
    * [[ulib/ldap]]
    * [[ulib/ldif]]
    * [[ulib/legacy]]
    * [[ulib/macosx]]
    * [[ulib/mkcrypt]]
    * [[ulib/modeline]]
    * [[ulib/network-manager-service]]
    * [[ulib/password]]
    * [[ulib/prefixes]]
    * [[ulib/PREFIXES-DEFAULTS]]
    * [[ulib/pretty]]
    * [[ulib/ptools]]
    * [[ulib/redhat]]
    * [[ulib/runs]]
    * [[ulib/runsmod]]
    * [[ulib/runsmod.defaults]]
    * [[ulib/semver]]
    * [[ulib/service]]
    * [[ulib/sysinfos]]
    * [[ulib/template]]
    * [[ulib/tiddlywiki]]
    * [[ulib/udir]]
    * [[ulib/uenv]]
    * [[ulib/uenv_update]]
    * [[ulib/uinc]]
    * [[ulib/uinst]]
    * [[ulib/ulib]]
    * [[ulib/ulibsh]]
    * [[ulib/vcs]]
    * [[ulib/virsh]]
    * [[ulib/webobjects]]
    * [[ulib/woinst]]
    * [[ulib/wondermonitor]]
    * [[ulib/wosign]]
    * [[ulib/wotaskd]]

    !! {{{compute_all_prefixes}}}
    !! {{{recompute_all_prefixes}}}

    !! {{{apache_resolvecert}}}
    {{{
    Calculer l'emplacement des certificats correspondant aux arguments $1 et
    $2 (qui correspondent aux options --conf et --dir de apache_addcert()),
    puis initialiser les variables $3(=cert), $4(=key) et $5(=ca)
    }}}
    !! {{{apache_addcert}}}
    !! {{{apache_autoconf}}}
    !! {{{apache_autoconf_localhosts}}}

    !! {{{get_default_apachebin_prefix}}}
    !! {{{get_default_apacheversion_prefix}}}
    !! {{{get_default_apachectl_prefix}}}
    !! {{{get_default_apachelogdir_prefix}}}
    !! {{{get_default_apachesslcertsdir_prefix}}}
    !! {{{get_default_apachesslkeysdir_prefix}}}
    !! {{{get_default_apacheconfdir_prefix}}}
    !! {{{get_default_apacheconf_prefix}}}
    !! {{{get_default_apacheavsitesdir_prefix}}}
    !! {{{get_default_apachesitesdir_prefix}}}
    !! {{{get_default_htdocsdir_prefix}}}
    !! {{{get_default_cgibindir_prefix}}}
    !! {{{compute_apache_prefixes}}}
    !! {{{recompute_apache_prefixes}}}
    !! {{{get_APACHEBIN_prefix}}}
    !! {{{get_APACHEVERSION_prefix}}}
    !! {{{get_APACHECTL_prefix}}}
    !! {{{get_APACHELOGDIR_prefix}}}
    !! {{{get_APACHESSLCERTSDIR_prefix}}}
    !! {{{get_APACHESSLKEYSDIR_prefix}}}
    !! {{{get_APACHECONFDIR_prefix}}}
    !! {{{get_APACHECONF_prefix}}}
    !! {{{get_APACHEAVSITESDIR_prefix}}}
    !! {{{get_APACHESITESDIR_prefix}}}
    !! {{{get_HTDOCSDIR_prefix}}}
    !! {{{get_CGIBINDIR_prefix}}}

    !! {{{parseheaders}}}
    !! {{{printheaders}}}
    !! {{{resetheaders}}}
    !! {{{copyall}}}
    !! {{{lawkcsv}}}
    !! {{{cawkcsv}}}
    !! {{{awkcsv}}}
    !! {{{lgrepcsv}}}
    !! {{{cgrepcsv}}}
    !! {{{grepcsv}}}
    !! {{{lawkfsv2csv}}}
    !! {{{cawkfsv2csv}}}
    !! {{{awkfsv2csv}}}
    !! {{{lmergecsv}}}
    {{{
    Fusionner sur la sortie standard les deux fichiers csv $1 et $2. La clé du
    fichier $1 est spécifiée par l'option --lkey et vaut 1 par défaut. La clé
    du fichier $2 est spécifiée par l'option --rkey et vaut 1 par défaut. Les
    valeurs des clés ne doivent pas faire plus de 64 caractères de long.
    }}}
    !! {{{readleft}}}
    !! {{{readright}}}
    !! {{{right2left}}}
    !! {{{cmergecsv}}}
    !! {{{mergecsv}}}
    !! {{{lsortcsv}}}
    {{{
    Trier le fichier csv $1. La clé du tri est spécifiée par l'option -k et
    vaut 1 par défaut. Les valeurs des clés ne doivent pas faire plus de 64
    caractères de long.
    }}}
    !! {{{csortcsv}}}
    !! {{{sortcsv}}}
    !! {{{ldumpcsv}}}
    !! {{{cdumpcsv}}}
    !! {{{dumpcsv}}}
    !! {{{lprintcsv}}}
    !! {{{cprintcsv}}}
    !! {{{printcsv}}}

    !! {{{parse_opts}}}
    {{{
    Analyser des arguments. Cette fonction doit être appelée avec une description
    des options à analyser, suivie des arguments proprement dits. En fonction des
    options rencontrées, certaines variables sont mises à jour.
    Les arguments de cette fonction sont donc de la forme 'optdescs -- args'
    }}}
    !! {{{parse_args_check}}}
    {{{
    Simplifier l'utilisation de parse_opts(). En entrée, le tableau args doit être
    initialisé avec la liste des options. En sortie, ce tableau contient la liste
    des arguments restant sur la ligne de commande. En cas d'erreur, retourner 1.
    Exemple d'utilisation:
    args=(...)
    parse_args_check "$@" || return; set -- "${args[@]}"
    }}}
    !! {{{parse_args}}}
    {{{
    Simplifier l'utilisation de parse_opts(). En entrée, le tableau args doit être
    initialisé avec la liste des options. En sortie, ce tableau contient la liste
    des arguments restant sur la ligne de commande. En cas d'erreur, quitter le
    script avec die()
    Exemple d'utilisation:
    args=(...)
    parse_args_check "$@"; set -- "${args[@]}"
    }}}
    !! {{{genparse}}}
    {{{
    Afficher une ligne de commande à évaluer pour simplifier l'utilisation de
    parse_opts(). Une fonction display_help() par défaut est définie et les
    options appropriées de parse_opts sont utilisées pour reconnaître les options
    spécifiées par les arguments.
    Cette fonction peut être utilisée de cette manière:
    HELP_DESC=...
    HELP_ARG_DESC=... # pour chaque arg
    eval "$(genparse [args...])"
    D'autres variables peuvent être définies: HELP_USAGE, HELP_OPTIONS,
    HELP_ARG_OPTION. Consulter le source pour connaitre leur utilisation
    Les arguments de cette fonction sont de la forme 'sansarg' pour une option
    simple qui ne prend pas d'argument ou 'avecarg=[default-value]' pour une
    option qui prend un argument. Les options générées sont des options
    longues. En l'occurence, les options générées sont respectivement '--sansarg'
    et '--avecarg:'
    Les variables et les options sont toujours en minuscule. Pour les variables,
    le caractère '-' est remplacé par '_'. Si une option contient une lettre en
    majuscule, l'option courte correspondante à cette lettre sera aussi reconnue.
    Par exemple, la commande suivante:
    genparse Force enCoding=utf-8 input= long-Option=
    affichera ceci:
    function display_help() {
    [ -n "$HELP_USAGE" ] || HELP_USAGE="USAGE
    $scriptname [options]"
    [ -n "$HELP_OPTIONS" ] || HELP_OPTIONS="OPTIONS
    ${HELP_FORCE_OPTION:-    -f, --force${HELP_FORCE_DESC:+
    $HELP_FORCE_DESC}}
    }}}

    !! {{{is_yes}}}
    {{{
    retourner vrai si $1 est une valeur "oui"
    }}}
    !! {{{is_no}}}
    {{{
    retourner vrai si $1 est une valeur "non"
    }}}
    !! {{{yesval}}}
    {{{
    normaliser une valeur vraie: si $1 est une valeur "oui", afficher 1, sinon
    afficher une chaine vide
    }}}
    !! {{{setb}}}
    {{{
    Lancer la commande $2..@ en supprimant la sortie standard. Si la commande
    retourne vrai, assigner la valeur 1 à la variable $1. Sinon, lui assigner la
    valeur ""
    note: en principe, la syntaxe est 'setb var cmd args...'. cependant, la
    syntaxe 'setb var=cmd args...' est supportée aussi
    }}}
    !! {{{evalb}}}
    {{{
    Lancer la commande $@ avec evalx() en supprimant la sortie standard. Si la
    commande retourne vrai, afficher 1. Sinon, afficher ""
    }}}
    !! {{{setxb}}}
    {{{
    équivalent à setx $1 evalb $2..@
    }}}

    !! {{{setx2}}}
    !! {{{rawecho}}}
    !! {{{rawecho_}}}
    !! {{{quote_arg}}}
    !! {{{quoted_arg}}}
    !! {{{quoted_args}}}
    !! {{{set_var}}}
    !! {{{set_var_cmd}}}
    !! {{{set_var_literal}}}
    !! {{{quote_awk}}}
    !! {{{quoted_awk}}}
    !! {{{quote_seds}}}
    !! {{{quote_form}}}
    !! {{{quoted_form}}}

    !! {{{echo_}}}
    {{{
    afficher la valeur $* sans passer à la ligne
    }}}
    !! {{{recho}}}
    {{{
    afficher une valeur brute. contrairement à la commande echo, ne reconnaitre
    aucune option (i.e. -e, -E, -n ne sont pas signifiants)
    }}}
    !! {{{recho_}}}
    {{{
    afficher une valeur brute, sans passer à la ligne. contrairement à la commande
    echo, ne reconnaitre aucune option (i.e. -e, -E, -n ne sont pas signifiants)
    }}}
    !! {{{should_quote}}}
    {{{
    Tester si la chaine $* doit être mise entre quotes
    }}}
    !! {{{qval}}}
    {{{
    Afficher la chaine $* quotée avec "
    }}}
    !! {{{qvalm}}}
    {{{
    Afficher la chaine $* quotée si nécessaire avec "
    }}}
    !! {{{qvalr}}}
    {{{
    Afficher la chaine $* quotée si nécessaire avec ", sauf si elle est vide
    }}}
    !! {{{qvals}}}
    {{{
    Afficher chaque argument de cette fonction quotée le cas échéant avec "
    Chaque valeur est séparée par un espace.
    }}}
    !! {{{qwc}}}
    {{{
    Dans la chaine $*, remplacer \ par \\, " par \", $ par \$, ` par \`, puis
    quoter la chaine avec ", sauf les wildcards * et ?
    Cela permet de quoter une chaine permettant de glober des fichiers, e.g
    eval "ls $(qwc "$value")"
    Note: la protection de ! n'est pas effectuée, parce que le comportement du
    shell est incohérent entre le shell interactif et les scripts. Pour une
    version plus robuste, il est nécessaire d'utiliser un programme externe tel
    que sed ou awk
    }}}
    !! {{{qlines}}}
    {{{
    Traiter chaque ligne de l'entrée standard pour en faire des chaines quotées
    avec '
    }}}
    !! {{{setv}}}
    {{{
    initialiser la variable $1 avec la valeur $2*
    note: en principe, la syntaxe est 'setv var values...'. cependant, la
    syntaxe 'setv var=values...' est supportée aussi
    }}}
    !! {{{echo_setv}}}
    {{{
    Afficher la commande qui serait lancée par setv "$@"
    }}}
    !! {{{setx}}}
    {{{
    syntaxe 1: setx var cmd
    initialiser la variable $1 avec le résultat de la commande "$2..@"
    note: en principe, la syntaxe est 'setx var cmd args...'. cependant, la
    syntaxe 'setx var=cmd args...' est supportée aussi
    syntaxe 2: setx -a array cmd
    initialiser le tableau $1 avec le résultat de la commande "$2..@", chaque
    ligne du résultat étant un élément du tableau
    note: en principe, la syntaxe est 'setx -a array cmd args...'. cependant, la
    syntaxe 'setx -a array=cmd args...' est supportée aussi
    }}}
    !! {{{evalx}}}
    {{{
    Implémenter une syntaxe lisible et naturelle permettant d'enchainer des
    traitements sur une valeur. Par exemple, la commande
    evalx cmd1... // cmd2... // cmd3...
    affiche le résultat de la commande "$(cmd3 $(cmd2 $(cmd1)))"
    Retourner le dernier code d'erreur non nul, ou 0 si toutes les commandes se
    sont exécutées sans erreur.
    }}}
    !! {{{setxx}}}
    {{{
    équivalent à setx $1 evalx $2..@
    }}}
    !! {{{evalp}}}
    {{{
    Implémenter une syntaxe alternative permettant d'enchainer des traitements sur
    un flux de données. Par exemple, la commande
    evalp cmd1... // cmd2... // cmd3...
    affiche le résultat de la commande "$(cmd1 | cmd2 | cmd3)"
    Typiquement, cette fonction permet de faciliter la construction d'un
    enchainement de commandes par programme, ou de faciliter l'utilisation de la
    fonction setx() pour récupérer le résultat d'un enchainement. Dans les autres
    cas, il est plus simple et naturel d'écrire les enchainements avec la syntaxe
    de bash.
    }}}
    !! {{{setxp}}}
    {{{
    équivalent à setx $1 evalp $2..@
    }}}
    !! {{{testx}}}
    {{{
    Faire un test unaire avec la commande [ sur une valeur calculée avec evalx.
    Utiliser la syntaxe 'testx op cmds...' e.g.
    testx -z cmd1 // cmd2
    }}}
    !! {{{test2x}}}
    {{{
    Faire une test binaire avec la commande [ entre une valeur spécifiée et une
    valeur calculée avec evalx. Utiliser la syntaxe 'test2x value op cmds...' e.g.
    test2x value == cmd1 // cmd2
    }}}
    !! {{{testrx}}}
    {{{
    Faire une test binaire avec la commande [[ entre une valeur spécifiée et une
    valeur calculée avec evalx. Utiliser la syntaxe 'testrx value op cmds...' e.g.
    testrx value == cmd1 // cmd2
    }}}
    !! {{{testp}}}
    {{{
    Faire un test unaire avec la commande [ sur une valeur calculée avec evalp.
    Utiliser la syntaxe 'testp op cmds...' e.g.
    testp -z cmd1 // cmd2
    }}}
    !! {{{test2p}}}
    {{{
    Faire une test binaire avec la commande [ entre une valeur spécifiée et une
    valeur calculée avec evalp. Utiliser la syntaxe 'test2p value op cmds...' e.g.
    test2p value == cmd1 // cmd2
    }}}
    !! {{{testrp}}}
    {{{
    Faire une test binaire avec la commande [[ entre une valeur spécifiée et une
    valeur calculée avec evalp. Utiliser la syntaxe 'testrp value op cmds...' e.g.
    testrp value == cmd1 // cmd2
    }}}
    !! {{{err2out}}}
    {{{
    lancer la commande $@ en redirigeant la sortie d'erreur sur la sortie standard
    }}}

    !! {{{isnum}}}
    {{{
    retourner vrai si $1 est une valeur numérique entière (positive ou négative)
    }}}
    !! {{{ispnum}}}
    {{{
    retourner vrai si $1 est une valeur numérique entière positive
    }}}
    !! {{{isrnum}}}
    {{{
    retourner vrai si $1 est une valeur numérique réelle (positive ou négative)
    le séparateur décimal peut être . ou ,
    }}}

    !! {{{qawk}}}
    {{{
    Dans la chaine $*, remplacer \ par \\ et " par \" et afficher la chaine
    entourée de guillemets. Ceci est utile pour quoter des valeur à insérer dans
    un script awk
    }}}
    !! {{{qseds}}}
    {{{
    Quoter la chaine $*, qui doit être utilisée comme chaine de recherche ou de
    remplacement de grep, sed ou awk
    }}}
    !! {{{qform}}}
    {{{
    Dans la chaine $* qui est de la forme "name=value", remplacer dans name et
    dans value '%' par '%25', '+' par '%2B', '&' par '%26', '=' par '%3D', ' ' par
    '+'
    }}}

    !! {{{splitfsep}}}
    {{{
    Découper $1 de la forme "first[SEPsecond]" entre first, qui est placé dans la
    variable $3(=first) et second, qui est placée dans la variable $4(=second). $2
    est la valeur SEP. Le découpage est faite sur la *première* occurence de SEP.
    }}}
    !! {{{splitfsep2}}}
    {{{
    Découper $1 de la forme "[firstSEP]second" entre first, qui est placé dans la
    variable $3(=first) et second, qui est placée dans la variable $4(=second). $2
    est la valeur SEP. Le découpage est faite sur la *première* occurence de SEP.
    }}}
    !! {{{splitlsep}}}
    {{{
    Découper $1 de la forme "first[SEPsecond]" entre first, qui est placé dans la
    variable $3(=first) et second, qui est placée dans la variable $4(=second). $2
    est la valeur SEP. Le découpage est faite sur la *dernière* occurence de SEP.
    }}}
    !! {{{splitlsep2}}}
    {{{
    Découper $1 de la forme "[firstSEP]second" entre first, qui est placé dans la
    variable $3(=first) et second, qui est placée dans la variable $4(=second). $2
    est la valeur SEP. Le découpage est faite sur la *dernière* occurence de SEP.
    }}}
    !! {{{splitvar}}}
    {{{
    Découper $1 de la forme name[=value] entre le nom, qui est placé dans la
    variable $2(=name) et la valeur, qui est placée dans la variable $3(=value)
    }}}
    !! {{{splitpath}}}
    {{{
    Découper $1 de la forme [dir/]name entre le répertoire, qui est placé dans la
    variable $2(=dir), et le nom du fichier, qui est placé dans la variable
    $3(=name)
    }}}
    !! {{{splitname}}}
    {{{
    Découper $1 de la forme basename[.ext] entre le nom de base du fichier, qui
    est placé dans la variable $2(=basename) et l'extension, qui est placée dans
    la variable $3(=ext)
    Attention, si $1 est un chemin, le résultat risque d'être faussé. Par exemple,
    'splitname a.b/c' ne donne pas le résultat escompté.
    }}}
    !! {{{splithost}}}
    {{{
    Découper $1 de la forme hostname[.domain] entre le nom d'hôte, qui est placé
    dans la variable $2(=hostname) et le domaine, qui est placée dans la variable
    $3(=domain)
    }}}
    !! {{{splituserhost}}}
    {{{
    Découper $1 de la forme [user@]host entre le nom de l'utilisateur, qui est placé
    dans la variable $2(=user) et le nom d'hôte, qui est placée dans la variable
    $3(=host)
    }}}
    !! {{{splitpair}}}
    {{{
    Découper $1 de la forme first[:second] entre la première valeur, qui est placé
    dans la variable $2(=src) et la deuxième valeur, qui est placée dans la variable
    $3(=dest)
    }}}
    !! {{{splitproxy}}}
    {{{
    Découper $1 de la forme http://[user:password@]host[:port]/ entre les valeurs
    $2(=host), $3(=port), $4(=user), $5(=password)
    }}}
    !! {{{spliturl}}}
    {{{
    Découper $1 de la forme scheme://[user:password@]host[:port]/path entre les
    valeurs $2(=scheme), $3(=user), $4(=password), $5(=host), $6(=port), $7(=path)
    }}}

    !! {{{straddp}}}
    {{{
    ajouter le préfixe $1 à $2*
    }}}
    !! {{{strdelp}}}
    {{{
    enlever le préfixe $1 à $2*
    }}}
    !! {{{strdelp2}}}
    {{{
    enlever le préfixe $1 le plus long à $2*
    }}}
    !! {{{stradds}}}
    {{{
    ajouter le suffixe $1 à $2*
    }}}
    !! {{{strdels}}}
    {{{
    enlever le suffixe $1 à $2*
    }}}
    !! {{{strdels2}}}
    {{{
    enlever le suffixe le plus long $1 à $2*
    }}}
    !! {{{strlower}}}
    {{{
    afficher en minuscule la valeur $*
    }}}
    !! {{{strlower1}}}
    {{{
    afficher la valeur $* après avoir converti la première lettre en minuscule
    }}}
    !! {{{strlowers}}}
    {{{
    afficher les valeurs $1..* après avoir converti leur première lettre en
    minuscule
    }}}
    !! {{{strupper}}}
    {{{
    afficher en majuscule la valeur $*
    }}}
    !! {{{strupper1}}}
    {{{
    afficher la valeur $* après avoir converti la première lettre en majuscule
    }}}
    !! {{{struppers}}}
    {{{
    afficher les valeurs $1..* après avoir converti leur première lettre en
    majuscule
    }}}
    !! {{{strmid}}}
    {{{
    Afficher la plage $1 de la valeur $2*. La plage peut être d'une des formes
    'start', '[start]:length'. Si start est négatif, le compte est effectué à
    partir de la fin de la chaine. Si length est négatif, il est rajouté à la
    longueur de la chaine à partir de start
    }}}
    !! {{{strrepl}}}
    {{{
    Remplacer dans la valeur $3* le motif $1 par la chaine $2. $1 peut commencer
    par l'un des caractères /, #, % pour indiquer le type de recherche
    }}}
    !! {{{first_char}}}
    {{{
    retourner le premier caractère de la chaine $*
    }}}
    !! {{{last_char}}}
    {{{
    retourner le dernier caractère de la chaine $*
    }}}
    !! {{{first_chars}}}
    {{{
    retourner tous les caractères de la chaine $*, excepté le dernier
    }}}
    !! {{{last_chars}}}
    {{{
    retourner tous les caractères de la chaine $*, excepté le premier
    }}}
    !! {{{first_char_is}}}
    {{{
    Tester si le premier caractère de la chaine $1 est $2
    }}}
    !! {{{last_char_is}}}
    {{{
    Tester si le dernier caractère de la chaine $1 est $2
    }}}
    !! {{{beginswith}}}
    {{{
    Tester si la chaine $1 commence par le wildcard $2
    }}}
    !! {{{endswith}}}
    {{{
    Tester si la chaine $1 se termine par le wildcard $2
    }}}

    !! {{{base_umove}}}
    {{{
    Outil de haut niveau pour déplacer un fichier ou un lien. Si c'est un lien qui
    est déplacé, la destination du lien est mise à jour si elle est relative.
    l'option '-d UPDATEDIR' permet de spécifier un répertoire dans lequel tous les
    liens qui pointent vers le fichier déplacé sont mis à jour si le déplacement
    du fichier se fait avec succès.
    }}}
    !! {{{base_udelete}}}
    {{{
    Outil de haut niveau pour supprimer un fichier ou un lien. Si on doit
    supprimer un fichier, et que l'option '-d UPDATEDIR' est spécifiée, et que des
    liens du répertoire UPDATEDIR pointent vers le fichier supprimé, ces liens
    sont supprimés aussi.
    }}}
    !! {{{base_ucopy}}}
    {{{
    Outil de haut niveau pour copier un fichier ou un lien. Si c'est un lien qui
    est copié, la destination du lien est mise à jour si elle est relative.
    }}}

    !! {{{setyesval}}}
    {{{
    mettre la valeur normalisée de la valeur "oui" de $2 dans la variable $1
    }}}
    !! {{{normyesval}}}
    {{{
    remplacer la valeur de la variable $1 par la valeur normalisée de sa valeur "oui"
    Si $2 est non vide, prendre cette valeur plutôt que la valeur de la variable $1
    }}}
    !! {{{normyesvals}}}
    {{{
    remplacer les valeur des variables $1..* par les valeurs normalisées
    respectives de leur valeur "oui"
    }}}
    !! {{{quote_in}}}
    {{{
    Comme quote_arg pour une chaine lue sur stdin
    }}}
    !! {{{quote_sin}}}
    {{{
    Pour la chaine lue sur stdin, remplacer ' par '\''. Cela permet de protéger une
    chaine à mettre entre quotes
    }}}
    !! {{{quote_sarg}}}
    {{{
    Dans la chaine $1, remplacer ' par '\''. Cette fonction utilise quote_sin,
    puisque le shell a des difficultés à faire le rechercher/remplacer approprié
    }}}
    !! {{{quoted_sarg}}}
    {{{
    Dans la chaine $1, remplacer ' par '\'', et afficher la chaine entourée de
    quotes
    }}}
    !! {{{quoted_sargs}}}
    {{{
    Comme quoted_sarg, mais tous les arguments sont quotés et affichés entourés de
    quotes, ce qui permet de construire des arguments d'une ligne de commande
    }}}
    !! {{{set_array_cmd}}}
    {{{
    Afficher la commande permettant d'initialiser le tableau $1 avec les valeurs:
    soit du tableau $2, soit de $3..$n si $2=="@"
    S'il n'y a que l'argument $1, alors afficher la commande permettant de
    recréer le tableau $1
    }}}
    !! {{{set_array}}}
    {{{
    Soit $1 un tableau à créer. Si $2=="@", créer le tableau $1 avec les valeurs
    $3..$n. Sinon, créer le tableau $1 avec les valeurs du tableau $2.
    Cette fonction n'existe que comme un pendant de set_var(), mais le véritable
    intérêt est la fonction set_array_cmd(). cf array_copy() pour une version plus
    efficace de la copie de tableaux
    }}}
    !! {{{array_count}}}
    {{{
    retourner le nombre d'éléments du tableau $1
    }}}
    !! {{{array_isempty}}}
    {{{
    tester si le tableau $1 est vide
    }}}
    !! {{{array_new}}}
    {{{
    créer un tableau vide dont le nom est $1
    }}}
    !! {{{array_add}}}
    {{{
    ajouter les valeurs $2..@ au tableau dont le nom est $1
    }}}
    !! {{{array_ins}}}
    {{{
    insérer les valeurs $2..@ au début du tableau dont le nom est $1
    }}}
    !! {{{array_del}}}
    {{{
    supprimer *les* valeurs $2 du tableau dont le nom est $1
    }}}
    !! {{{array_addu}}}
    {{{
    ajouter la valeur $2 au tableau dont le nom est $1, si la valeur n'y est pas
    déjà. Retourner vrai si la valeur a été ajoutée
    }}}
    !! {{{array_set}}}
    !! {{{array_insu}}}
    {{{
    insérer la valeur $2 au début du tableau tableau dont le nom est $1, si la
    valeur n'y est pas déjà. Retourner vrai si la valeur a été ajoutée.
    }}}
    !! {{{array_fillrange}}}
    {{{
    Initialiser le tableau $1 avec les nombres de $2(=1) à $3(=10) avec un step de $4(=1)
    }}}
    !! {{{array_eq}}}
    {{{
    tester l'égalité des tableaux $1 et $2
    }}}
    !! {{{array_contains}}}
    {{{
    tester si le tableau dont le nom est $1 contient la valeur $2
    }}}
    !! {{{array_icontains}}}
    {{{
    tester si le tableau dont le nom est $1 contient la valeur $2, sans tenir
    compte de la casse
    }}}
    !! {{{array_find}}}
    {{{
    si le tableau $1 contient la valeur $2, retourner l'index de la valeur. Si le
    tableau $3 est spécifié, retourner la valeur à l'index dans ce tableau
    }}}
    !! {{{array_reverse}}}
    {{{
    Inverser l'ordre des élément du tableau $1
    }}}
    !! {{{array_replace}}}
    {{{
    dans le tableau $1, remplacer toutes les occurences de $2 par $3..*
    }}}
    !! {{{array_each}}}
    {{{
    Pour chacune des valeurs 'v' du tableau $1, appeler la fonction $2 avec les
    arguments '$v $3..$n'
    }}}
    !! {{{array_map}}}
    {{{
    Pour chacune des valeurs 'v' du tableau $1, appeler la fonction $2 avec les
    arguments '$v $3..$n', et remplacer la valeur par le résultat de la fonction
    }}}
    !! {{{first_value}}}
    {{{
    retourner la première valeur du tableau $1
    }}}
    !! {{{last_value}}}
    {{{
    retourner la dernière valeur du tableau $1
    }}}
    !! {{{array_copy}}}
    {{{
    copier le contenu du tableau $2 dans le tableau $1
    }}}
    !! {{{array_copy_firsts}}}
    {{{
    copier tous les valeurs du tableau $2(=$1) dans le tableau $1, excepté la dernière
    }}}
    !! {{{array_del_last}}}
    !! {{{array_copy_lasts}}}
    {{{
    copier tous les valeurs du tableau $2(=$1) dans le tableau $1, excepté la première
    }}}
    !! {{{array_del_first}}}
    !! {{{array_extend}}}
    {{{
    ajouter le contenu du tableau $2 au tableau $1
    }}}
    !! {{{array_extendu}}}
    {{{
    ajouter chacune des valeurs du tableau $2 au tableau $1, si ces valeurs n'y
    sont pas déjà. Retourner vrai si au moins une valeur a été ajoutée
    }}}
    !! {{{array_extend_firsts}}}
    {{{
    ajouter toutes les valeurs du tableau $2 dans le tableau $1, excepté la dernière
    }}}
    !! {{{array_extend_lasts}}}
    {{{
    ajouter toutes les valeurs du tableau $2 dans le tableau $1, excepté la première
    }}}
    !! {{{array_xsplit}}}
    {{{
    créer le tableau $1 avec chaque élément de $2 (un ensemble d'éléments séparés
    par $3, qui vaut ':' par défaut).
    }}}
    !! {{{array_split}}}
    {{{
    créer le tableau $1 avec chaque élément de $2 (un ensemble d'éléments séparés
    par $3, qui vaut ':' par défaut). Les éléments vides sont ignorés. par exemple
    "a::b" est équivalent à "a:b"
    }}}
    !! {{{array_from_path}}}
    !! {{{array_from_xlines}}}
    {{{
    créer le tableau $1 avec chaque ligne de $2.
    }}}
    !! {{{array_from_lines}}}
    {{{
    créer le tableau $1 avec chaque ligne de $2. Les lignes vides sont ignorés.
    }}}
    !! {{{array_join}}}
    {{{
    afficher le contenu du tableau dont le nom est $1 sous forme d'une liste de
    valeurs séparées par $2 (par défaut, une virgule)
    Si $1=="@", alors les éléments du tableaux sont les arguments de la fonction à
    partir de $3
    Si $1!="@" et que le tableau est vide, afficher $3
    Si $1!="@", $4 et $5 sont des préfixes et suffixes à rajouter à chaque élément
    }}}
    !! {{{array_mapjoin}}}
    {{{
    map le tableau $1 avec la fonction $2, puis afficher le résultat en séparant
    chaque élément par $3. Les arguments et la sémantique sont les mêmes que pour
    array_join en tenant compte de l'argument supplémentaire $2 qui est la
    fonction pour array_map (les autres arguments sont décalés en conséquence)
    }}}
    !! {{{array_to_lines}}}
    {{{
    afficher le tableau dont le nom est $1 sous forme de lignes
    }}}
    !! {{{array_to_path}}}
    {{{
    afficher le tableau dont le nom est $1 sous forme d'une liste de chemins
    séparés par ':')
    }}}
    !! {{{array_fix_paths}}}
    {{{
    Corriger les valeurs du tableau $1. Les valeurs contenant le séparateur
    $2(=':') sont séparées en plusieurs valeurs. Par exemple avec le tableau
    input=(a b:c), le résultat est input=(a b c)
    }}}
    !! {{{get_date_rfc822}}}
    !! {{{get_date_fr}}}
    !! {{{get_time_fr}}}
    !! {{{parse_date}}}
    !! {{{udelpath}}}
    {{{
    supprimer le chemin $1 de $2(=PATH)
    }}}
    !! {{{uaddpath}}}
    {{{
    Ajouter le chemin $1 à la fin, dans $2(=PATH), s'il n'y existe pas déjà
    }}}
    !! {{{uinspathm}}}
    {{{
    Ajouter le chemin $1 au début, dans $2(=PATH), s'il n'y existe pas déjà
    }}}
    !! {{{uinspath}}}
    {{{
    S'assurer que le chemin $1 soit au début de $2(=PATH)
    }}}
    !! {{{withpath}}}
    {{{
    tester si le chemin est relatif à . ou à .., ou est absolu. i.e 'withpath a/b'
    renvoie faux alors que 'withpath ./a/b' renvoie vrai
    }}}
    !! {{{withext}}}
    {{{
    tester si le fichier a une extension
    }}}
    !! {{{normpath}}}
    {{{
    normaliser le chemin $1, qui est soit absolu, soit relatif à $2 (qui vaut
    $(pwd) par défaut)
    }}}
    !! {{{abspath}}}
    {{{
    Retourner un chemin absolu vers $1. Si $2 est non nul et si $1 est un chemin
    relatif, alors $1 est exprimé par rapport à $2, sinon il est exprimé par
    rapport au répertoire courant.
    Si le chemin n'existe pas, il n'est PAS normalisé. Sinon, les meilleurs
    efforts sont faits pour normaliser le chemin.
    }}}
    !! {{{parentdirs}}}
    {{{
    Obtenir la liste de tous les parents du répertoire $2 dans le tableau $1, du
    répertoire $2 vers la racine. Si $3 commence par 'r' (comme reverse), l'ordre
    est inversé: le tableau contient les répertoire de la racine vers $2.
    }}}
    !! {{{ppath}}}
    {{{
    Dans un chemin *absolu*, remplacer "$HOME" par "~" et "$(pwd)/" par "", afin
    que le chemin soit plus facile à lire. Le répertoire courant est spécifié par
    $2 ou $(pwd) si $2 est vide
    }}}
    !! {{{relpath}}}
    {{{
    Afficher le chemin relatif de $1 par rapport à $2. Si $2 n'est pas spécifié,
    on prend le répertoire courant. Si $1 ou $2 ne sont pas des chemins absolus,
    il sont transformés en chemins absolus par rapport à $3. Si $1==$2, retourner
    une chaine vide
    }}}
    !! {{{relpathx}}}
    {{{
    Comme relpath, mais pour un chemin vers un exécutable qu'il faut lancer:
    s'assurer qu'il y a une spécification de chemin, e.g. ./script
    }}}
    !! {{{withinpath}}}
    {{{
    Tester si le chemin absolu $2 se trouve dans le chemin absolu "$1" (appelée
    barrière). Soit un chemin P, on considère que P est dans P. Si ce comportement
    n'est pas souhaité, $3(=N) doit valoir O, auquel cas P est dans Q implique que
    P != Q.
    }}}
    !! {{{safe_abspath}}}
    {{{
    Afficher le chemin absolu de $1, par rapport à $2, si et seulement si le
    chemin résultat ne se trouve pas en dehors de la barrière $3. Si $2 n'est pas
    spécifié, prendre le répertoire courant. S'il est relatif, l'exprimer par
    rapport au répertoire courant. Si $3 est relatif, l'exprimer par rapport à $2.
    Si le chemin résultat est sité en dehors de la barrière, ne rien afficher et
    retourner un code d'erreur.
    Si le chemin $1 n'existe pas, il n'est PAS normalisé. Sinon, les meilleurs
    efforts sont faits pour normaliser le chemin résultat.
    }}}
    !! {{{safe_relpath}}}
    {{{
    Afficher le chemin relatif de $1 par rapport à $2 si et seulement si le chemin
    résultat ne se trouve pas en dehors de la barrière $3. Si $2 n'est pas
    spécifié, prendre le répertoire courant. S'il est relatif, l'exprimer par
    rapport au répertoire courant. Si $3 est relatif, l'exprimer par rapport à $2.
    Si le chemin résultat est sité en dehors de la barrière, ne rien afficher et
    retourner un code d'erreur.
    }}}
    !! {{{splitwcs}}}
    {{{
    Découper un nom de chemin $1 entre la partie sans wildcards, qui est placée dans
    la variables $2(=basedir), et la partie avec wildcards, qui est placée dans la
    variable $3(=filespec)
    }}}
    !! {{{deref}}}
    {{{
    Retourner un chemin absolu vers le fichier $1, dans lequel toutes les
    composantes "lien symbolique" ont été supprimées.
    DEPRECATED: Cette fonction est dépréciée. Utiliser à la place readlinkm()
    }}}
    !! {{{readlinka}}}
    {{{
    Afficher un chemin absolu vers la destination du fichier $1. Si $1 n'est pas
    un lien, afficher simplement le chemin du fichier
    }}}
    !! {{{readlinkm}}}
    {{{
    Retourner un chemin absolu vers le fichier $1, dans lequel toutes les
    composantes "lien symbolique" ont été supprimées. Il n'est pas requis que les
    composantes du chemin existent.
    }}}
    !! {{{path_if_test}}}
    {{{
    afficher un chemin si le fichier $2 existe (en utilisant l'opérateur $1) dans
    l'un des chemins absolus $4..n. si $3==relative, afficher le chemin relatif,
    sinon le chemin absolu. note: $3 peut être de la forme relative:path, auquel
    cas le chemin affiché est exprimé relativement à path
    }}}
    !! {{{update_link}}}
    {{{
    mettre à jour le lien $2 pour qu'il pointe vers le fichier $1
    }}}
    !! {{{update_links}}}
    {{{
    Mettre à jour les liens $2..@ pour qu'ils pointent vers la nouvelle
    destination $1
    }}}
    !! {{{move_link}}}
    {{{
    Déplacer le lien $1 vers $2, et mettre à jour la destination du lien si
    elle est exprimée de façon relative
    Si $1 n'est pas un lien, le déplacer normalement avec mv
    }}}
    !! {{{copy_link}}}
    {{{
    Copier le lien $1 vers $2, et mettre à jour la destination du lien si
    elle est exprimée de façon relative
    Si $1 n'est pas un lien, le copier normalement avec cp
    }}}
    !! {{{array_find_links}}}
    {{{
    Chercher dans le répertoire $3 (qui est par défaut le répertoire courant)
    les liens vers le fichier $2, et ajouter leurs chemins absolus dans le
    tableau $1
    }}}
    !! {{{list_links}}}
    {{{
    Chercher dans le répertoire $2 les liens vers le fichier $1, et les
    afficher, un par ligne.
    }}}
    !! {{{move_file}}}
    {{{
    Déplacer le fichier $1 vers $2, et mettre à jour les liens $3..@ pour
    qu'ils pointent vers la nouvelle destination
    }}}
    !! {{{get_nblines}}}
    {{{
    Afficher le nombre de lignes d'un fichier
    }}}
    !! {{{mktempf}}}
    {{{
    générer un fichier temporaire et retourner son nom
    }}}
    !! {{{mktempd}}}
    {{{
    générer un répertoire temporaire et retourner son nom
    }}}
    !! {{{mkdirof}}}
    {{{
    Créer le répertoire correspondant à un fichier
    }}}
    !! {{{cp_a}}}
    {{{
    copier des fichiers en gardant le maximum de propriétés
    }}}
    !! {{{cp_R}}}
    {{{
    copier des fichiers récursivement, en suivant les liens symboliques
    }}}
    !! {{{quietgrep}}}
    {{{
    tester la présence d'un pattern dans un fichier
    }}}
    !! {{{quietdiff}}}
    {{{
    tester si deux fichiers sont identiques
    }}}
    !! {{{testsame}}}
    {{{
    tester si deux fichiers sont identiques/différents
    }}}
    !! {{{testdiff}}}
    !! {{{testupdated}}}
    {{{
    test si $2 n'existe pas ou si $1 est différent de $2
    }}}
    !! {{{testnewer}}}
    {{{
    test si $2 n'existe pas ou si $1 est plus récent que $2
    }}}
    !! {{{ps_all}}}
    {{{
    afficher tous les processus avec le maximum d'informations
    }}}
    !! {{{progexists}}}
    {{{
    tester l'existence d'un programme dans le PATH
    }}}
    !! {{{has_python}}}
    {{{
    tester la présence de python
    }}}
    !! {{{has_gawk}}}
    {{{
    tester la présence de gnuawk
    }}}
    !! {{{is_root}}}
    {{{
    tester si on est root
    }}}
    !! {{{source_ifexists}}}
    {{{
    sourcer un fichier s'il existe
    }}}
    !! {{{is_running}}}
    {{{
    tester si un programme dont on donne le PID tourne
    }}}
    !! {{{sedi}}}
    {{{
    Lancer sed sur un fichier en le modifiant en place
    }}}
    !! {{{csort}}}
    {{{
    Lancer sort avec LANG=C pour éviter les problèmes avec la locale. en effet,
    avec LANG!=C, sort utilise les règles de la locale pour le tri, et par
    exemple, avec LANG=fr_FR.UTF-8, la locale indique que les ponctuations doivent
    être ignorées.
    }}}
    !! {{{lsort}}}
    !! {{{cgrep}}}
    {{{
    Lancer grep avec LANG=C pour éviter les problèmes avec la locale. cf csort
    pour une explication.
    }}}
    !! {{{lgrep}}}
    !! {{{csed}}}
    {{{
    Lancer sed avec LANG=C pour éviter les problèmes avec la locale. cf csort pour
    une explication.
    }}}
    !! {{{lsed}}}
    !! {{{cawk}}}
    {{{
    Lancer awk avec LANG=C pour éviter les problèmes avec la locale. cf csort pour
    une explication.
    }}}
    !! {{{lawk}}}
    !! {{{cdiff}}}
    {{{
    Lancer diff avec LANG=C pour éviter les problèmes avec la locale. cf csort
    pour une explication.
    }}}
    !! {{{ldiff}}}
    !! {{{fix_mode}}}
    {{{
    Si le fichier $1 n'est pas writable, le rendre writable temporairement. Si
    nécessaire, le fichier est créé.
    Cette fonction s'utilise de cette façon:
    mode="$(fix_mode file)"
    ...
    unfix_mode file "$mode"
    }}}
    !! {{{unfix_mode}}}
    {{{
    Restaurer le mode $2 du fichier $1 traité par fix_mode
    }}}
    !! {{{get_mode}}}
    {{{
    Obtenir le mode du fichier $1, en le créant si nécessaire. A utiliser avec
    unfix_mode pour restaurer le mode d'un fichier qui a été traité avec un
    fichier temporaire intermédiaire
    }}}
    !! {{{rm_maybe}}}
    {{{
    Supprimer les fichiers dont on donne la liste. Si aucun fichier n'est
    spécifié, cette fonction est un NOP
    }}}
    !! {{{cpdir}}}
    {{{
    copier un fichier dans un répertoire, ou le contenu d'un répertoire dans un
    autre répertoire, que le répertoire source soit un lien symbolique ou
    non. Cette fonction existe parce que le comportement de "cp_a src dest" n'est
    pas consistant selon les plateformes, surtout si src est un lien symbolique
    sur un répertoire: parfois on copie le lien, parfois on copie le contenu du
    répertoire, parfois on copie le répertoire...
    La copie est faite avec rsync si possible. Les options du tableau
    __CPDIR_RSYNC_ARGS sont rajoutées aux options standard de rsync.
    }}}
    !! {{{cpnovcs}}}
    {{{
    copier le fichier/répertoire $1 *dans* le *répertoire* $2 avec rsync. Les
    options du tableau __CPNOVCS_RSYNC_ARGS sont rajoutées aux options standard
    de rsync.
    Si $1 est un répertoire, la copie est faite en ignorant les sous-répertoires
    de VCS (.svn, CVS). En ce qui concerne les répertoire de VCS, git aussi est
    supporté, mais uniquement s'il est à la racine du transfert.
    Si $1 se termine par un '/', c'est le contenu du répertoire qui est copié, pas
    le répertoire lui-même. Si rsync n'est pas trouvé sur le système, alors on
    fait une copie standard qui inclue les répertoires de VCS.
    }}}
    !! {{{cpvcs}}}
    {{{
    comme cpnovcs, mais ne pas ignorer les répertoires de VCS
    }}}
    !! {{{cpdirnovcs}}}
    {{{
    Le pendant de cpdir, mais en ignorant les sous-répertoires de VCS: copier le
    contenu du répertoire $1 dans le répertoire $2
    }}}
    !! {{{doinplace}}}
    {{{
    Filtrer le fichier $1 à travers la commande $2..$*, puis remplacer le fichier
    s'il n'y a pas eu d'erreur. Retourner le code d'erreur de la commande. Si $1
    n'est pas spécifié ou vaut -, filtrer l'entrée standard vers la sortie
    standard.
    La variante doinplacef remplace le fichier quelque soit le code de retour de
    la commande. A utiliser avec des commandes comme grep qui peuvent retourner
    FAUX s'ils ne trouvent pas le motif
    }}}
    !! {{{doinplacef}}}
    !! {{{stripnl}}}
    {{{
    Supprimer les caractères de fin de ligne de la chaine en entrée
    }}}
    !! {{{nl2lf}}}
    !! {{{nl2crlf}}}
    !! {{{nl2cr}}}
    !! {{{list_all}}}
    {{{
    Lister les fichiers ou répertoires du répertoire $1, un par ligne
    Les répertoires . et .. sont enlevés de la liste
    $1=un répertoire dont le contenu doit être listé
    $2..@=un ensemble de patterns pour le listage
    }}}
    !! {{{list_files}}}
    {{{
    Lister les fichiers du répertoire $1, un par ligne
    $1=un répertoire dont le contenu doit être listé.
    $2..@=un ensemble de patterns pour le listage
    }}}
    !! {{{list_dirs}}}
    {{{
    Lister les répertoires du répertoire $1, un par ligne
    Les répertoires . et .. sont enlevés de la liste
    $1=un répertoire dont le contenu doit être listé.
    $2..@=un ensemble de patterns pour le listage
    }}}
    !! {{{array_lsall}}}
    {{{
    Lister les fichiers avec `list_all $2 $3...`, et les mettre dans le
    tableau $1. Le tableau contient les chemins complets, par seulement les
    noms comme avec list_all
    }}}
    !! {{{array_lsdirs}}}
    {{{
    Lister les fichiers avec `list_dirs $2 $3...`, et les mettre dans le
    tableau $1. Le tableau contient les chemins complets, par seulement les
    noms comme avec list_dirs
    }}}
    !! {{{array_lsfiles}}}
    {{{
    Lister les fichiers avec `list_files $2 $3...`, et les mettre dans le
    tableau $1. Le tableau contient les chemins complets, par seulement les
    noms comme avec list_files
    }}}
    !! {{{filter_empty}}}
    {{{
    Filtrer l'entrée standard en enlevant les lignes vides
    }}}
    !! {{{filter_vcspath}}}
    {{{
    L'entrée standard étant une liste de chemins, filtrer les fichiers et
    répertoire qui ont un rapport avec subversion ou git
    }}}
    !! {{{merge_contlines}}}
    {{{
    Avec les lignes lues sur stdin, fusionner celles qui se terminent par \ avec
    les suivantes.
    }}}
    !! {{{filter_comment}}}
    {{{
    Filtrer un fichier de configuration lu sur stdin en enlevant les commentaires
    et les lignes vides.
    Avec $1==-m, fusionner les lignes qui se terminent par \ avec les suivantes
    Comme filter_conf(), les commentaires doivent être sur une ligne à part.
    Contrairement à filter_conf, il n'est pas nécessaire que le caractère '#' soit
    en début de ligne: il peut apparaitre après des espaces et des tabulations. De
    même, une ligne qui ne contient que des espaces et des tabulations est
    considérée comme vide.
    }}}
    !! {{{filter_conf}}}
    {{{
    filtrer un fichier de configuration lu sur stdin en enlevant les commentaires
    et les lignes vides. Une ligne n'est considérée commentaire que si '#' est un
    première position. Utiliser filter_comment() si les commentaire peuvent
    commencer par des caractères espace et tabulation.
    Si $1==-m, fusionner les lignes qui se terminent par \ avec les suivantes
    }}}
    !! {{{is_archive}}}
    {{{
    tester si l'extension d'un fichier indique que c'est une archive
    }}}
    !! {{{extract_archive}}}
    {{{
    Extraire le contenu de l'archive $1 dans le répertoire ${2:-.}
    }}}
    !! {{{get_archive_basename}}}
    {{{
    Obtenir le nom de base de l'archive $1
    }}}
    !! {{{get_archive_appname}}}
    {{{
    Obtenir le nom probable de l'application ou du framework contenu dans
    l'archive $1, e.g:
    get_archive_versionsuffix app-0.1.tgz
    --> app
    }}}
    !! {{{get_archive_versionsuffix}}}
    {{{
    Obtenir la valeur probable de la version de l'application ou du framework
    contenu dans l'archive $1, avec le caractère de séparation, e.g:
    get_archive_versionsuffix app-0.1.tgz
    --> -0.1
    }}}
    !! {{{get_archive_version}}}
    {{{
    Obtenir la valeur probable de la version de l'application ou du framework
    contenu dans l'archive $1, e.g:
    get_archive_versionsuffix app-0.1.tgz
    --> 0.1
    }}}
    !! {{{dump_usernames}}}
    {{{
    Placer dans le tableau $1 la liste des utilisateurs du système
    Cette implémentation consulte /etc/passwd et liste tous les utilisateurs dont
    le homedir se trouve dans /home, et dont l'uid est >=500
    }}}
    !! {{{resolv_ips}}}
    {{{
    Placer dans le tableau $1(=ips) la liste des adresses ip correspondant à
    l'hôte $2. La résolution est effectuée avec la commande host.
    }}}
    !! {{{resolv_hosts}}}
    {{{
    Placer dans le tableau $1(=hosts) la liste des hôtes correspondant à
    l'adresse ip $2. La résolution est effectuée avec la commande host.
    }}}
    !! {{{runscript_as}}}
    {{{
    Utiliser bash pour lancer le script $2 avec les arguments $3..$n afin qu'il
    tourne avec les droits d'un autre user $1(=root). Si $2=exec, utiliser exec
    pour lancer le script et ses arguments qui commencent à partir de $3, ce qui
    fait que cette fonction ne retourne pas.
    Attention! cette fonction ne teste pas avec si on est déjà le user $1. Il y a
    donc un risque de boucle infinie si on ne teste pas le user courant.
    }}}
    !! {{{runscript_as_root}}}
    {{{
    Utiliser bash pour lancer le script $1 avec les arguments $2..$* avec les
    droits de root. Si on est déjà en root, le script est simplement lancé. Sinon,
    utiliser runscript_as pour lancer le script avec les droits de root.
    }}}
    !! {{{run_as}}}
    {{{
    Relancer le script courant afin qu'il tourne avec les droits d'un autre user
    $1(=root)
    Attention! cette fonction ne teste pas avec si on est déjà ce user. Il y a
    donc un risque de boucle infinie si on ne teste pas le user courant.
    Il faut lancer cette fonction avec les arguments du script en cours. Par
    exemple::
    run_as root "$@"
    Si $2=--noexec, on n'utilise pas la fonction exec, ce qui fait que la fonction
    retourne. Sinon, on peut considérer que cette fonction ne retourne jamais
    }}}
    !! {{{run_as_root}}}
    {{{
    relancer le script courant afin qu'il tourne en root si on est pas en déjà
    root. Sinon, cette fonction est un nop.
    }}}
    !! {{{check_user}}}
    {{{
    Vérifier si le user courant est l'un des users $1..*
    }}}
    !! {{{ensure_user}}}
    {{{
    Vérifier si le user courant est l'un des users $1..N où N est la position du
    premier "--". Si ce n'est pas le cas et que l'on est root, relancer le script
    avec ce user grâce à la fonction run_as()
    Retourner 1 si ce n'était pas le bon user. Retourner 10 si ce n'était pas le
    bon user et que l'on n'est pas root (donc impossible à priori de relancer le
    script avec le bon user). Retourner 11 si l'utilisateur a choisi de ne pas
    lancer le script avec le bon utilisateur
    A utiliser de cette manière:
    if ensure_user users... -- args; then
    # ... on est avec le bon user; faire les opérations
    else
    # ... ce code n'est exécuté que si une erreur s'est produite, ou si ce
    # n'était pas le bon user et que l'option --noexec est utilisée
    fi
    }}}
    !! {{{check_hostname}}}
    {{{
    Vérifier si le hostname courant est l'un des hôtes $1..*
    localhost matche toujours
    }}}
    !! {{{check_userhostname}}}
    {{{
    Vérifier si le hostname et éventuellement le user courant sont l'un des
    arguments $1..*
    Chaque argument est de la forme [user@]host, mais le test ne tient compte que
    du nom de l'hôte, sans tenir compte du domaine. Si le user n'est pas spécifié,
    le test ne porte que sur hostname.
    }}}
    !! {{{ensure_hostname}}}
    {{{
    Vérifier si le hostname et le user courant sont l'un des arguments $1..*
    Chaque argument est de la forme [user@]host, mais le test ne tient compte que
    du nom de l'hôte, sans tenir compte du domaine.
    Si user est spécifié:
    - Si on est sur le bon hôte mais pas le bon user, ensure_user est lancé avec
    l'argument approprié pour relancer le script
    Si l'argument était de la forme userhost:path, le répertoire courant est
    changé avant de lancer le script avec le bon utilisateur.
    Sinon (si user n'est pas spécifié):
    - Si on n'est pas sur le bon hôte, après confirmation le script est lancé avec
    ssh sur l'hôte distant avec le user spécifié (qui vaut par défaut root). Ce
    script DOIT exister sur l'hôte distant avec le même chemin.
    Si l'argument était de la forme userhost:path, le répertoire courant distant
    est changé avant de lancer le script
    Si on est avec le bon user sur le bon hôte, le répertoire courant n'est jamais
    changé.
    Retourner 1 si ce n'était pas le bon user. Retourner 10 si ce n'était pas le
    bon user et que l'on n'est pas root (donc impossible à priori de relancer le
    script avec le bon user). Retourner 11 si l'utilisateur a choisi de ne pas
    lancer le script sur l'hôte distant. Retourner 12 si une erreur s'est produite
    avec ssh.
    A utiliser de cette manière:
    if ensure_hostname user@host... -- args; then
    # ... on est [avec le bon user] sur le bon hôte; faire les opérations
    else
    # ... ce code n'est exécuté que si une erreur s'est produite, ou si ce
    # n'était pas le bon user et que l'option --noexec est utilisée
    fi
    }}}
    !! {{{sqvals}}}
    !! {{{quoted_values}}}
    !! {{{formatcsv}}}
    !! {{{awkdef}}}
    {{{
    Afficher un script à insérer au début d'un script awk. Ce script définit dans
    une section BEGIN{} les variables donnés en arguments, et avec l'option -f,
    des fonctions utiles. Si une valeur ne ressemble pas à une définition de
    variable, l'analyse des variables s'arrête et le reste des arguments est
    inséré tel quel. Cette fonction peut être utilisée de cette manière:
    awk "$(awkdef -f var=value... 'script awk')"
    Normalement, les variables définies sont scalaires, avec une syntaxe de la
    forme var[:type]=value. type peut valoir str ou int, pour forcer le type de la
    variable créée dans awk.
    Il est possible d'utiliser la syntaxe awk_array[@]=bash_array ou array[@] (qui
    est équivalente à array[@]=array) pour initialiser le tableau awk_array, qui
    contiendra toute les valeurs du tableau nommé bash_array, avec les indices de
    1 à N, N étant le nombre d'éléments du tableau bash_array. La variable
    awk_array_count est aussi initialisée, et contient le nombre d'éléments du
    tableau
    La syntaxe "awk_array[@]=<\n..." permet de spécifier les valeurs du tableau,
    une par ligne, e.g:
    $'values[@]=<\nvalue1\nvalue2'
    pour un tableau values qui contiendra deux valeurs: value1 et value2
    Avec l'option -f, des fonctions supplémentaires sont définies. Elles sont
    décrites dans le module awk.
    }}}
    !! {{{lawkrun}}}
    {{{
    wrapper pour lancer awk avec un script préparé par awkdef. Les définitions et
    les arguments sont séparés par --, e.g.
    awkrun var0=value0 var1=value1 script -- input0 input1
    }}}
    !! {{{cawkrun}}}
    !! {{{awkrun}}}
    !! {{{lf_trylock}}}
    {{{
    USAGE
    lf_trylock [-h max_hours] /path/to/lockfile
    OPTIONS
    lockfile
    fichier qui doit contenir le verrou
    -h max_hours
    Nombre d'heures (par défaut 4) au bout duquel afficher stale
    Sinon, afficher locked
    Retourne 0 si le verrou a été placé correctement. Il ne faut pas oublier de
    supprimer le fichier. Le mieux est de le faire supprimer automatiquement par
    autoclean:
    lockfile=...
    case "$(lf_trylock "$lockfile")" in
    locked) ...;;
    stale) ...;;
    esac
    autoclean "$lockfile"
    Sinon, retourner 1 et afficher l'une des deux valeurs suivantes:
    - stale si le verrou a déjà été placé, depuis au moins max_hours heures
    - locked si le verrou a déjà été placé
    - retry si une erreur s'est produite pendant la pose du verrou ou sa
    lecture. Cela peut se produire si les droits ne sont pas suffisants pour
    écrire dans le répertoire destination, ou si le fichier a été supprimé
    avant sa lecture (race-condition). Dans ce dernier cas, reessayer permettra
    d'acquérir le verrou
    }}}
    !! {{{pidfile_set}}}
    {{{
    USAGE
    pidfile_set [-p pid] /path/to/pidfile
    OPTIONS
    pidfile
    fichier qui doit contenir le pid du script
    -p pid
    spécifier le pid. par défaut, utiliser $$
    -r  si pidfile existe mais que le processus ne tourne plus, faire
    comme si le fichier n'existe pas.
    Retourner 0 si le pid a été correctement écrit dans le fichier. Ce fichier
    sera supprimé automatiquement en fin de script
    Retourner 1 si le fichier existe déjà et que le processus est en train de
    tourner.
    Retourner 2 si le fichier existe déjà mais que le processus ne tourne plus.
    Retourner 10 si autre erreur grave s'est produite (par exemple, s'il manque le
    chemin vers pidfile, ou si le fichier n'est pas accessible en écriture.)
    }}}
    !! {{{pidfile_check}}}
    {{{
    USAGE
    pidfile_check /path/to/pidfile
    OPTIONS
    pidfile
    fichier qui doit contenir le pid d'un processus
    Cette fonction permet de vérifier si le processus associé à un fichier de pid
    est en train de tourner.
    Retourner 0 si le fichier de pid existe et que le process du pid spécifié est
    en train de tourner. Retourner 1 sinon.
    Retourner 10 si erreur grave s'est produite (par exemple, s'il manque le
    chemin vers pidfile, ou si le fichier n'est pas accessible en lecture.)
    }}}
    !! {{{page_maybe}}}
    {{{
    Utiliser less, si possible, pour afficher le flux en entrée. Si le terminal
    n'est pas interactif ou si le nombre de lignes en entrée est inférieur au
    nombre de lignes du terminal, afficher simplement le flux.
    Les arguments de cette fonction sont passés à less
    }}}
    !! {{{utools_local}}}
    {{{
    Afficher les commandes pour rendre locales certaines variables en fonction des
    arguments:
    - opts rend locale args, pour utiliser parse_opts() à l'intérieur d'une
    fonction.
    - verbosity et interaction rendent respectivement locales __verbosity et
    __interaction. Ceci est utile pour pouvoir appeler sans risque de pollution
    de l'environnement une fonction qui utilise parse_opts() avec les
    définitions de PRETTYOPTS.
    Si aucun arguments n'est fourni, toutes les définitions sont affichées.
    }}}
    !! {{{stdredir}}}
    {{{
    Lancer la commande $4..@ en redirigeant stdin depuis $1, stdout vers $2,
    stderr vers $3. Si $1 est vide ou vaut /dev/stdin, la redirection n'est
    pas faite. Si $2 est vide ou vaut /dev/stdout, la redirection n'est pas
    faite. Si $3 est vide ou vaut /dev/stderr, la redirection n'est pas faite.
    Cette fonction existe parce que sur certaines versions de bash, il semble
    que les redirections /dev/std* ne sont pas traitées de façon particulière.
    De plus, sur des technologies telles que OpenVZ, les chemins /dev/std* ne
    sont pas créés (parce que /proc/self/fd/* n'est pas accessible). Donc,
    dans de rares cas où le script tourne sur OpenVZ avec une version de bash
    qui est buggée, la redirection n'est pas faite correctement.
    }}}
    !! {{{isatty}}}
    {{{
    tester si STDOUT n'est pas une redirection
    }}}
    !! {{{in_isatty}}}
    {{{
    tester si STDIN n'est pas une redirection
    }}}
    !! {{{out_isatty}}}
    {{{
    tester si STDOUT n'est pas une redirection
    }}}
    !! {{{err_isatty}}}
    {{{
    tester si STDERR n'est pas une redirection
    }}}
    !! {{{die}}}
    !! {{{die_unless}}}
    {{{
    Afficher $-1 et quitter le script avec die() si la commande $1..-2 retourne
    FAUX
    }}}
    !! {{{eerror_unless}}}
    {{{
    Afficher $-1 avec eerror() et retourner $? si la commande $1..-2 retourne FAUX
    }}}
    !! {{{die_if}}}
    {{{
    Afficher $-1 et quitter le script avec die() si la commande $1..-2 retourne
    VRAI
    }}}
    !! {{{eerror_if}}}
    {{{
    Afficher $-1 avec eerror() et retourner le code d'erreur 1 si la commande
    $1..-2 retourne VRAI
    }}}
    !! {{{noerror}}}
    {{{
    lancer la commande "$@" et masquer son code de retour
    }}}
    !! {{{noout}}}
    {{{
    lancer la commande "$@" en supprimant sa sortie standard
    }}}
    !! {{{noerr}}}
    {{{
    lancer la commande "$@" en supprimant sa sortie d'erreur
    }}}
    !! {{{tooenc}}}
    {{{
    Transformer la valeur $1 de l'encoding $2(=$OENC) vers l'encoding de sortie
    $3=($UTOOLS_OUTPUT_ENCODING)
    }}}
    !! {{{uecho}}}
    !! {{{tooenc_}}}
    {{{
    Transformer la valeur $1 de l'encoding $2(=$OENC) vers l'encoding de sortie
    $3=($UTOOLS_OUTPUT_ENCODING)
    }}}
    !! {{{uecho_}}}
    !! {{{toienc}}}
    {{{
    Transformer la valeur $1 de $2(=$IENC) vers l'encoding d'entrée
    $3(=$UTOOLS_INPUT_ENCODING)
    }}}
    !! {{{uread}}}
    {{{
    Lire une valeur sur stdin et la placer dans la variable $1. On assume que la
    valeur en entrée est encodée dans l'encoding d'entrée par défaut
    }}}
    !! {{{stooenc}}}
    {{{
    Transformer la valeur lue sur stdin de $OENC vers l'encoding de sortie par
    défaut ($UTOOLS_OUTPUT_ENCODING)
    }}}
    !! {{{stoienc}}}
    {{{
    Transformer la valeur lue sur stdin de $IENC vers l'encoding d'entrée par
    défaut ($UTOOLS_INPUT_ENCODING)
    }}}
    !! {{{elogto}}}
    {{{
    Activer UTOOLS_EDATE et rediriger STDOUT et STDERR vers le fichier $1
    Si deux fichiers sont spécifiés, rediriger STDOUT vers $1 et STDERR vers $2
    Si aucun fichier n'est spécifié, ne pas faire de redirection
    Si la redirection est activée, forcer l'utilisation de l'encoding UTF8
    Si UTOOLS_ELOG_OVERWRITE=1, alors le fichier en sortie est écrasé. Sinon, les
    lignes en sortie lui sont ajoutées
    }}}
    !! {{{set_verbosity}}}
    !! {{{set_interaction}}}
    !! {{{show_error}}}
    {{{
    tester respectivement si on doit afficher les messages d'erreur,
    d'avertissement, d'information, de debug
    }}}
    !! {{{show_warn}}}
    !! {{{show_info}}}
    !! {{{show_verbose}}}
    !! {{{show_debug}}}
    !! {{{check_verbosity}}}
    !! {{{get_verbosity_option}}}
    !! {{{check_interaction}}}
    !! {{{is_interaction}}}
    !! {{{get_interaction_option}}}
    !! {{{eflush}}}
    {{{
    Afficher les messages en attente
    }}}
    !! {{{eclearp}}}
    {{{
    Supprimer les message en attente
    }}}
    !! {{{eerror}}}
    {{{
    Afficher un message d'erreur
    }}}
    !! {{{ewarn}}}
    {{{
    Afficher un message d'avertissement
    }}}
    !! {{{enote}}}
    {{{
    Afficher un message d'information de même niveau qu'un avertissement
    }}}
    !! {{{ebanner}}}
    {{{
    Afficher un message très important encadré, puis attendre 5 secondes
    }}}
    !! {{{eimportant}}}
    {{{
    Afficher un message très important
    }}}
    !! {{{eattention}}}
    {{{
    Afficher un message important
    }}}
    !! {{{einfo}}}
    {{{
    Afficher un message d'information
    }}}
    !! {{{eecho}}}
    {{{
    Afficher un message d'information sans préfixe
    }}}
    !! {{{eecho_}}}
    !! {{{edebug}}}
    {{{
    Afficher un message de debug
    }}}
    !! {{{trace}}}
    {{{
    Afficher la commande $1..@, la lancer, puis afficher son code d'erreur si une
    erreur se produit
    }}}
    !! {{{trace_error}}}
    {{{
    Lancer la commande $1..@, puis afficher son code d'erreur si une erreur se
    produit. La différence avec trace() est que la commande n'est affichée que si
    une erreur se produit.
    }}}
    !! {{{etitle}}}
    {{{
    Afficher le titre $1, qui est le début éventuel d'une section. Les section
    imbriquées sont affichées indentées. La section n'est pas terminée, et il faut
    la terminer explicitement avec eend, sauf dans certains cas précis:
    - Si $2..$* est spécifié, c'est une commande. Lancer la commande dans le
    contexte de la section. Puis, la section est automatiquement terminée sauf si
    l'option -s est spécifiée, auquel cas la section reste ouverte. Si l'option -p
    est spécifiée, eclearp() est appelé pour purger les messages en attente
    - Dans le cas contraire, l'option -s est ignorée: la section doit toujours
    être terminée explicitement.
    La fonction etitled() est comme etitle(), mais le titre n'est pas affiché
    immédiatement. L'affichage effectif est effectué dès qu'une fonction e* est
    utilisée. Ceci permet, avec la fonction eclearp(), de ne pas afficher de titre
    pour une section vide.
    }}}
    !! {{{etitled}}}
    !! {{{estep}}}
    {{{
    Afficher la description d'une opération. Cette fonction est particulièrement
    appropriée dans le contexte d'un etitle.
    Les variantes e (error), w (warning), n (note), i (info) permettent d'afficher
    des couleurs différentes, mais toutes sont du niveau info.
    }}}
    !! {{{estepe}}}
    !! {{{estepw}}}
    !! {{{estepn}}}
    !! {{{estepi}}}
    !! {{{estep_}}}
    !! {{{estepe_}}}
    !! {{{estepw_}}}
    !! {{{estepn_}}}
    !! {{{estepi_}}}
    !! {{{ebegin}}}
    {{{
    Afficher le message $1, qui décrit le début d'une opération. Cette fonction
    débute une section, qu'il faut terminer avec eend.
    Si $2..$* est spécifié, c'est une commande. Lancer la commande dans le
    contexte de la section. Puis, la section est terminée automatiquement, sauf si
    l'option -s est spécifiée, auquel cas la section reste ouverte.
    }}}
    !! {{{edot}}}
    {{{
    Afficher une étape d'une opération, matérialisée par un point '.' ou une
    croix 'x' en cas de succès ou d'erreur. Cette fonction est particulièrement
    appropriée dans le contexte d'un ebegin.
    }}}
    !! {{{edotw}}}
    {{{
    Afficher un avertissement comme étape d'une opération, matérialisée par une
    lettre 'w' (typiquement de couleur jaune). Cette fonction est particulièrement
    appropriée dans le contexte d'un ebegin.
    }}}
    !! {{{ewait}}}
    {{{
    Afficher les étapes d'une opération qui dure, matérialisées par des '+' toutes
    les secondes tant que le processus $1 tourne.
    A utiliser de cette manière:
    ebegin "msg"
    cmd &
    ewait $!
    eend
    }}}
    !! {{{eend}}}
    {{{
    Terminer une section.
    Avec l'option -c, remettre à zéro toutes les informations de section
    Si la section en cours est un ebegin, afficher la fin de l'opération: [ok] ou
    [error] en fonction du code de retour de la dernière commande (ou de $1 si
    cette valeur est donnée)
    Si la section en cours est un etitle, marquer la fin de la section concernée
    par le titre.
    }}}
    !! {{{elinedots}}}
    {{{
    Afficher un message comme avec ebegin "$1", puis afficher un point '.' pour
    chaque ligne lue sur stdin. Cela permet de suivre une opération. En mode
    DEBUG, afficher la ligne affichée plutôt qu'un point.
    Si $2..$* sont spécifiés, lancer la commande et suivre sa sortie. Ainsi,
    'elinedots msg cmd args' est un raccourci pour 'cmd args | elinedots msg'
    }}}
    !! {{{ask_yesno}}}
    {{{
    Afficher le message $1 suivi de [oN] ou [On] suivant que $2 vaut O ou N, puis
    lire la réponse. Retourner 0 si la réponse est vrai, 1 sinon.
    Si $1 est une option, elle est utilisée avec check_interaction pour savoir si
    on est en mode interactif ou non. A ce moment-là, les valeurs sont décalées
    ($2=message, $3=default)
    Si $2 vaut C, la valeur par défaut est N si on est interactif, O sinon
    Si $2 vaut X, la valeur par défaut est O si on est interactif, N sinon
    }}}
    !! {{{read_value}}}
    {{{
    Afficher le message $1 suivi de la valeur par défaut [$3] si elle est non
    vide, puis lire la valeur donnée par l'utilisateur. Cette valeur doit être non
    vide si $4(=O) est vrai. La valeur saisie est placée dans la variable
    $2(=value)
    Si $1 est une option, elle est utilisée avec check_interaction pour savoir si
    on est en mode interactif ou non. A ce moment-là, les valeurs sont décalées
    ($2=message, $3=variable, $4=default, $5=required)
    En mode non interactif, c'est la valeur par défaut qui est sélectionnée. Si
    l'utilisateur requière que la valeur soit non vide et que la valeur par défaut
    est vide, afficher un message d'erreur et retourner faux
    read_password() est comme read_value(), mais la valeur saisie n'est pas
    affichée, ce qui la rend appropriée pour la lecture d'un mot de passe.
    }}}
    !! {{{read_password}}}
    !! {{{simple_menu}}}
    {{{
    Afficher un menu simple dont les éléments sont les valeurs du tableau
    $2(=options). L'option choisie est placée dans la variable $1(=option)
    -t TITLE: spécifier le titre du menu
    -m YOUR_CHOICE: spécifier le message d'invite pour la sélection de l'option
    -d DEFAULT: spécifier l'option par défaut. Par défaut, prendre la valeur
    actuelle de la variable $1(=option)
    }}}
    !! {{{actions_menu}}}
    {{{
    Afficher un menu dont les éléments sont les valeurs du tableau $4(=options),
    et une liste d'actions tirées du tableau $3(=actions). L'option choisie est
    placée dans la variable $2(=option). L'action choisie est placée dans la
    variable $1(=action)
    Un choix est saisi sous la forme [action]num_option
    -t TITLE: spécifier le titre du menu
    -m OPT_YOUR_CHOICE: spécifier le message d'invite pour la sélection de
    l'action et de l'option
    -M ACT_YOUR_CHOICE: spécifier le message d'invite dans le cas où aucune option
    n'est disponible. Dans ce cas, seules les actions vides sont possibles.
    -e VOID_ACTION: spécifier qu'une action est vide, c'est à dire qu'elle ne
    requière pas d'être associée à une option. Par défaut, la dernière action
    est classée dans cette catégorie puisque c'est l'action "quitter"
    -d DEFAULT_ACTION: choisir l'action par défaut. par défaut, c'est la première
    action.
    -q QUIT_ACTION: choisir l'option "quitter" qui provoque la sortie du menu sans
    choix. par défaut, c'est la dernière action.
    -o DEFAULT_OPTION: choisir l'option par défaut. par défaut, prendre la valeur
    actuelle de la variable $2(=option)
    }}}
    !! {{{autoclean}}}
    {{{
    Ajouter $1..$n à la liste des fichiers à supprimer à la fin du programme
    }}}
    !! {{{ac_cleanall}}}
    {{{
    Supprimer *tous* les fichiers temporaires gérés par autoclean tout de suite.
    }}}
    !! {{{ac_clean}}}
    {{{
    Supprimer les fichier temporaires $1..$* si et seulement s'ils ont été générés
    par ac_set_tmpfile ou ac_set_tmpdir
    }}}
    !! {{{ac_set_tmpfile}}}
    {{{
    Créer un fichier temporaire avec le motif $2, l'ajouter à la liste des
    fichiers à supprimer en fin de programme, et mettre sa valeur dans la
    variable $1
    En mode debug, si ($5 est vide ou ${!5} est une valeur vraie), et si $3 n'est
    pas vide, prendre ce fichier au lieu de générer un nouveau fichier
    temporaire. Si $4==keep, ne pas écraser le fichier $3 s'il existe.
    }}}
    !! {{{ac_set_tmpdir}}}
    {{{
    Créer un répertoire temporaire avec le motif $2, l'ajouter à la liste des
    fichiers à supprimer en fin de programme, et mettre sa valeur dans la
    variable $1
    En mode debug, si ($4 est vide ou ${!4} est une valeur vraie), et si $3 n'est
    pas vide, prendre ce nom de répertoire au lieu de créer un nouveau répertoire
    temporaire
    }}}
    !! {{{debug_tee}}}
    {{{
    En mode debug, passer le flux à travers la commande 'tee "$@"'. Sinon, le flux
    est passé inchangé.
    }}}
    !! {{{get_user_defaults_file}}}
    {{{
    Afficher le chemin vers le fichier utilisateur à éditer pour qu'il soit chargé
    par 'set_defaults $1'. Ce fichier n'existe pas forcément; il faut peut-être le
    créer.
    }}}
    !! {{{get_defaults_files}}}
    {{{
    Initialiser le tableau $1(=defaults) avec la liste des fichiers qui seraient
    chargés par la commande 'set_defaults $2..N'
    }}}
    !! {{{set_defaults}}}
    {{{
    Pour chaque argument, sourcer /etc/default/$arg *et* (en priorité
    ~/etc/default.$HOSTNAME/$arg ou à défaut ~/etc/default/$arg) si ceux-ci
    existent. *Sinon*, lire $scriptdir/lib/default/$arg si ce fichier existe
    }}}
    !! {{{myhost}}}
    {{{
    Afficher le nom d'hôte pleinement qualifié, en faisant appel à la commande
    hostname. Par comparaison, $MYHOST est fourni par bash.
    }}}
    !! {{{myhostname}}}
    {{{
    Afficher le nom d'hôte sans domaine, en faisant appel à la commande
    hostname. Par comparaison, $MYHOSTNAME est fourni par bash.
    }}}

    !! {{{is_cgi}}}
    {{{
    Tester si on est lancé comme un script CGI
    }}}
    !! {{{ctype_header}}}
    {{{
    Générer une en-tête Content-Type: avec la valeur $1[=text/html]
    }}}
    !! {{{cdisp_header}}}
    {{{
    Générer une en-tête Content-Disposition: avec le type $2[=attachment] et
    le nom de fichier $1[=result]
    }}}
    !! {{{nocache_header}}}
    {{{
    Générer des en-têtes qui désactivent la mise en cache du contenu
    }}}
    !! {{{cgicontent}}}
    {{{
    Générer les en-têtes nécessaire avant de servir le contenu.
    $1(=text/html) est le type de contenu. S'il faut servir le contenu avec
    une disposition "attachment", $2 est le nom de fichier à proposer à
    l'utilisateur. Si $3 est spécifié, c'est le chemin vers le fichier dont le
    contenu doit être servi.
    $4..* sont des en-têtes supplémentaires à rajouter
    }}}
    !! {{{cgicontent_nocache}}}
    {{{
    Générer les en-têtes nécessaire avant de servir le contenu. Rajouter les
    entêtes pour désactiver la mise en cache.
    $1(=text/html) est le type de contenu. S'il faut servir le contenu avec
    une disposition "attachment", $2 est le nom de fichier à proposer à
    l'utilisateur. Si $3 est spécifié, c'est le chemin vers le fichier dont le
    contenu doit être servi.
    $4..* sont des en-têtes supplémentaires à rajouter
    }}}
    !! {{{cgierror}}}
    {{{
    Afficher les en-têtes pour désactiver la mise en cache, puis afficher un
    message d'erreur puis arrêter le script
    }}}
    !! {{{cgiredirect}}}
    {{{
    Afficher les en-têtes pour rediriger le client vers la page $1 puis
    arrêter le script
    }}}

    !! {{{cgiparams}}}
    !! {{{cgilsxml}}}
    !! {{{cgiupload}}}

    !! {{{conf_enable}}}
    {{{
    Dans le fichier de configuration $1, activer les paramètres $2..*
    Chaque argument de cette fonction correspond à une directive du fichier de
    configuration et doit être de la forme name[=value]
    Dans tous les cas, toutes les directives de ce nom sont recherchées et
    décommentées. Si value est précisée, les directives sont mises à jour. Si
    la directive ne figure pas dans le fichier, elle y est rajoutée à la fin
    avec la valeur spécifiée.
    Retourner 0 si une modification a été faite dans le fichier, 1 sinon
    }}}
    !! {{{conf_enableq}}}
    {{{
    Comme conf_enable(), mais s'assure que les valeurs sont quotées dans le
    fichier. Ceci permet de stocker des valeurs avec des espaces ou des
    caractères spéciaux.
    }}}
    !! {{{conf_disable}}}
    {{{
    Dans le fichier de configuration $1, désactiver les paramètres $2..*
    Chaque argument de cette fonction correspond à une directive du fichier de
    configuration et doit être de la forme name[=value]
    Toutes les directives de ce noms sont recherchées et commentées. La valeur
    si elle est spécifiée, est ignorée. Si la directive ne figure pas dans le
    fichier, c'est un NOP.
    Retourner 0 si une modification a été faite dans le fichier, 1 sinon
    }}}
    !! {{{conf_append}}}
    {{{
    Dans le fichier de configuration $1, augmenter les valeurs des variables
    correspondant aux paramètres $2..*
    Chaque argument de cette fonction correspond à une variable du fichier de
    configuration, et doit être de la forme name=value
    Une ligne 'name="${name:+$name:}$value"' est générée à la fin du fichier
    de configuration.
    Par défaut, le séparateur CONF_APPEND_SEP vaut ':', mais il est possible
    de changer cette valeur, de façon globale
    Retourner 0 si une modification a été faite dans le fichier, 1 sinon
    }}}
    !! {{{conf_array_append}}}
    {{{
    Dans le fichier de configuration $1, augmenter les valeurs des variables
    de tableau correspondant aux paramètres $2..*
    Chaque argument de cette fonction correspond à une variable du fichier de
    configuration, et doit être de la forme name=value
    Une ligne name=("${name[@]}" "$value") est générée à la fin du fichier de
    configuration
    Retourner 0 si une modification a été faite dans le fichier, 1 sinon
    }}}
    !! {{{conf_check}}}
    {{{
    Dans le fichier de configuration $1, tester si tous les paramètres $2..*
    sont présents.
    Chaque argument de cette fonction correspond à une variable du fichier de
    configuration, et doit être de la forme name[=value]
    Si une valeur est spécifiée, vérifier que le fichier contient la valeur
    correspondante. Sinon, tester uniquement la présence de la directive.
    }}}
    !! {{{aconf_enable}}}
    {{{
    Dans le fichier de configuration $1, activer les paramètres $2..*
    Chaque argument de cette fonction correspond à une directive du fichier de
    configuration et doit être de la forme name[=value]
    Toutes les directives de ce nom sont recherchées et décommentées, et la
    valeur mise à jour. Si la directive ne figure pas dans le fichier, elle y
    est rajoutée à la fin. A cause du mode opératoire, cette fonction ne
    convient pas pour les directives dont le nom peut apparaitre plusieurs
    fois dans le fichier
    Retourner 0 si une modification a été faite dans le fichier, 1 sinon
    }}}
    !! {{{aconf_disable}}}
    {{{
    Dans le fichier de configuration $1, désactiver les paramètres $2..*
    Chaque argument de cette fonction correspond à une directive du fichier de
    configuration et doit être de la forme name[=value]
    Si la valeur est précisée, la directive correspondant à ce nom et cette
    valeur est recherchée et commentée. Sinon, toutes les directives de ce
    noms sont recherchées et commentées. Si la directive ne figure pas dans le
    fichier, c'est un NOP.
    Retourner 0 si une modification a été faite dans le fichier, 1 sinon
    }}}
    !! {{{aconf_append}}}
    {{{
    Dans le fichier de configuration $1, ajouter des directives correspondant
    aux paramètres $2..*
    Chaque argument de cette fonction correspond à une directive du fichier de
    configuration et doit être de la forme name=value
    Une ligne '$name $value' est ajoutée à la fin du fichier de configuration
    Retourner 0 si une modification a été faite dans le fichier, 1 sinon
    }}}
    !! {{{aconf_array_append}}}
    !! {{{aconf_check}}}
    {{{
    Dans le fichier de configuration $1, tester si tous les paramètres $2..*
    sont présents.
    Chaque argument de cette fonction correspond à une variable du fichier de
    configuration, et doit être de la forme name[=value]
    Si une valeur est spécifiée, vérifier que le fichier contient la valeur
    correspondante. Sinon, tester uniquement la présence de la directive.
    }}}
    !! {{{mconf_enable}}}
    {{{
    Dans le fichier de configuration $1, activer les paramètres $3..* de la
    section $2
    Chaque argument de cette fonction correspond à une directive du fichier de
    configuration et doit être de la forme name[=value]
    Toutes les directives de ce nom sont recherchées et décommentées, et la
    valeur mise à jour. Si la directive ne figure pas dans le fichier, elle y
    est rajoutée à la fin. A cause du mode opératoire, cette fonction ne
    convient pas pour les directives dont le nom peut apparaitre plusieurs
    fois dans le fichier
    Retourner 0 si une modification a été faite dans le fichier, 1 sinon
    Cette fonction nécessite gawk et ignore la locale
    }}}
    !! {{{mconf_disable}}}
    {{{
    Dans le fichier de configuration $1, désactiver les paramètres $3..* de la
    section $2.
    Chaque argument de cette fonction correspond à une directive du fichier de
    configuration et doit être de la forme name[=value]
    Si la valeur est précisée, la directive correspondant à ce nom et cette
    valeur est recherchée et commentée. Sinon, toutes les directives de ce
    noms sont recherchées et commentées. Si la directive ne figure pas dans le
    fichier, c'est un NOP.
    Retourner 0 si une modification a été faite dans le fichier, 1 sinon
    Cette fonction nécessite gawk et ignore la locale
    }}}
    !! {{{mconf_append}}}
    {{{
    Dans le fichier de configuration $1, ajouter des directives correspondant
    aux paramètres $3..* dans la section $2
    Chaque argument de cette fonction correspond à une directive du fichier de
    configuration et doit être de la forme name=value
    Une ligne '$name = $value' est ajoutée à la fin de la section, qui est
    créée si nécessaire à la fin du fichier de configuration
    Retourner 0 si une modification a été faite dans le fichier, 1 sinon
    Cette fonction nécessite gawk et ignore la locale
    }}}
    !! {{{mconf_array_append}}}
    !! {{{mconf_check}}}
    {{{
    Dans le fichier de configuration $1, tester si tous les paramètres $3..*
    sont présents dans la section $2
    Chaque argument de cette fonction correspond à une variable du fichier de
    configuration, et doit être de la forme name[=value]
    Si une valeur est spécifiée, vérifier que le fichier contient la valeur
    correspondante. Sinon, tester uniquement la présence de la directive.
    Cette fonction nécessite gawk et ignore la locale
    }}}
    !! {{{gconf_addline}}}
    {{{
    USAGE
    gconf_addline configfile -a BEGIN -z END NEWLINE
    Dans le fichier de configuration $1, ajouter la ligne NEWLINE entre les lignes
    BEGIN et END.
    -a BEGIN
    Spécifier une expression pour matcher une ligne de type BEGIN. Si
    cette option n'est pas spécifiée, on considère que le début de fichier
    matche la ligne BEGIN: la ligne NEWLINE est ajoutée dès que possible.
    Les lignes sont matchées dans l'ordre, i.e. avec '-a 1 -a 2', il faut
    d'abord trouver la ligne 1 puis la ligne 2, sinon, le test n'est pas
    concluant.
    -t LINE
    Si après avoir matché toutes les lignes BEGIN, la ligne LINE est
    rencontrée, alors considérer que la ligne à rajouter existe déjà et
    qu'il ne faut pas la rajouter de nouveau
    -r LINE
    Si après avoir matché toutes les lignes BEGIN, la ligne LINE est
    rencontrée, alors considérer que la ligne à rajouter existe et qu'il
    faut la mettre à jour. Supprimer la ligne existante et la remplacer
    par la nouvelle ligne.
    -z END
    Spécifier une expression pour matcher la ligne de type END. Que cette
    option soit ou non spécifiée, on considère toujours que la fin de
    fichier matche la ligne END. Ainsi, si END n'est pas trouvée, la ligne
    NEWLINE est ajoutée à la fin du fichier.
    Dès que la ligne END est rencontrée, et si aucun des tests -t ou -r
    n'est concluant, alors ajouter la nouvelle ligne avant celle-ci
    -n MAX[=1]
    Ajouter au plus MAX occurences de NEWLINE. Après avoir matché END, le
    cycle recommence, au plus MAX-1 fois. Utiliser MAX=-1 pour désactiver
    la limite
    Cette fonction nécessite gawk et ignore la locale
    Retourner 0 si l'ajout s'est fait correctement. Retourner 1 si BEGIN n'a
    pas été trouvé, et donc aucun ajout n'a été effectué. Retourner 2 si une
    erreur quelconque s'est produite
    }}}
    !! {{{writelines_maybe}}}

    !! {{{add_to_crontab}}}
    !! {{{remove_from_crontab}}}
    !! {{{disable_in_crontab}}}
    !! {{{enable_in_crontab}}}
    !! {{{ctnow}}}
    {{{
    date +"%-M %-H %-d %-m %u"
    }}}
    !! {{{ctresolve}}}
    !! {{{get_default_crontabdir_prefix}}}
    !! {{{compute_crontab_prefixes}}}
    !! {{{recompute_crontab_prefixes}}}
    !! {{{get_CRONTABDIR_prefix}}}

    !! {{{pkg_check}}}
    {{{
    Vérifier que les packages sont installés sur le système
    }}}
    !! {{{pkg_update}}}
    {{{
    Mettre à jour la liste des packages silencieusement sans confirmation
    }}}
    !! {{{pkg_upgrade}}}
    {{{
    Mettre à jour la liste des packages silencieusement sans confirmation
    }}}
    !! {{{pkg_install}}}
    {{{
    Installer les packages silencieusement et sans confirmation
    }}}
    !! {{{pkg_installm}}}
    {{{
    Installer les packages silencieusement et sans confirmation
    Retourner 0 si au moins un des packages a été installé. Sinon, les
    packages n'ont pas été installés, soit parce qu'ils sont déjà installé,
    soit parce qu'il y a eu une erreur.
    }}}
    !! {{{pkg_check_install}}}
    {{{
    Si le programme $1 n'existe pas, alors installer les packages $2..$@
    S'il n'y a pas d'arguments $2..$@ utiliser $1 comme nom de package
    Retourner 0 si au moins un des packages a été installé
    }}}
    !! {{{service_disable}}}
    {{{
    Désactiver le service $1 pour qu'il ne se lance pas automatiquement au
    démarrage
    }}}
    !! {{{service_enable}}}
    {{{
    Activer le service $1 pour qu'il se lance automatiquement au démarrage
    }}}
    !! {{{network_parse_confbr}}}
    {{{
    network_parse_confbr "$confbr" br ifaces
    }}}
    !! {{{network_format_confbr}}}
    {{{
    network_format_confbr "$br" ifaces --> "br:ifaces"
    }}}
    !! {{{network_parse_confip}}}
    {{{
    network_parse_confip "$confip" iface gateway ipsuffixes
    }}}
    !! {{{network_parse_ipsuffix}}}
    {{{
    network_parse_ipsuffix "$ipsuffix" ip suffix
    }}}
    !! {{{network_format_confip}}}
    {{{
    network_format_confip "$iface" "$gateway" ipsuffixes --> "iface//gateway:ipsuffixes"
    }}}
    !! {{{network_format_ipsuffix}}}
    {{{
    network_format_ipsuffix "$ip" "$suffix" --> "ip/suffix"
    }}}
    !! {{{network_fix_confbrs}}}
    {{{
    normaliser le tableau $1(=confbrs): fusionner les doublons
    }}}
    !! {{{network_fix_confips}}}
    {{{
    normaliser le tableau $1(=confips): fusionner les doublons, spécifier le
    suffixe /24 par défaut, etc. $2 est le cas échéant l'interface associée
    aux adresses ip non qualifiées
    }}}
    !! {{{network_fix_mainiface}}}
    {{{
    A partir des valeurs des tableaux $1(=confbrs) et $2(=confips), et de
    l'interface principale $3, déterminer l'interface principale. Si $3 est
    spécifié, c'est la valeur sélectionnée. Sinon, si un bridge existe, c'est
    le premier bridge qui est sélectionné. Sinon, la première interface est
    sélectionnée. Sinon, on prend eth0.
    Ensuite, réorganiser les tableaux de façon que confips[0] devienne la
    configuration ip de l'interface principale.
    }}}
    !! {{{network_fix_confs}}}
    !! {{{network_set_confbrs}}}
    {{{
    initialiser $1(=confbrs) avec l'état des bridges sur le système courant
    }}}
    !! {{{network_set_confips}}}
    {{{
    initialiser le tableau $1(=confips) avec l'état des interfaces sur le
    système courant
    }}}
    !! {{{network_interfaces_check_confbr}}}
    {{{
    Vérifier que la configuration du bridge $1, dont les membres sont les
    interfaces du tableau $2(=ifaces) est faite dans le fichier
    $3(=/etc/network/interfaces)
    }}}
    !! {{{network_interfaces_check_confip}}}
    {{{
    Vérifier que la configuration de l'interface $1, avec la passerelle $2,
    avec les adresses IP du tabbleau $3(=ipsuffixes) est faite dans le fichier
    $4(=/etc/network/interfaces)
    }}}
    !! {{{network_interfaces_remove_iface}}}
    {{{
    Supprimer dans le fichier $2(=/etc/network/interfaces) toute la
    configuration qui concerne l'interface $1
    }}}
    !! {{{network_interfaces_remove_ifaces}}}
    {{{
    Supprimer dans le fichier $2(=/etc/network/interfaces) toute la
    configuration qui concerne les interfaces du tableau $1=(ifaces)
    }}}
    !! {{{network_interfaces_remove_confbr}}}
    {{{
    Supprimer dans le fichier $3(=/etc/network/interfaces) toute la
    configuration qui concerne le bridge $1, et dont les interfaces sont
    listées dans le tableau $2(=ifaces)
    }}}
    !! {{{network_interfaces_add_confip}}}
    {{{
    ajouter dans le fichier $4(=/etc/network/interfaces) la configuration pour
    l'interface $1, avec éventuellement la passerelle $2, et les adresses ips
    telles qu'elles sont définies dans le table $3(=ipsuffixes)
    }}}
    !! {{{network_interfaces_add_confbr}}}
    {{{
    ajouter dans le fichier $4(=/etc/network/interfaces) la configuration pour
    le bridge $1, avec la liste des interfaces dans le tableau $2(=ifaces) et
    la liste des configurations des adresses des interfaces dans le tableau
    $3(=confips)
    }}}
    !! {{{network_fix_hostname}}}
    !! {{{network_fix_mailname}}}
    !! {{{network_fix_exim4}}}
    !! {{{network_fix_postfix}}}
    !! {{{network_fix_hosts}}}
    !! {{{network_config}}}
    {{{
    (Re)configurer le réseau sur l'hôte courant.
    $1 (host) est le nom d'hôte.
    $2 (confips) est le nom d'un tableau contenant la configuration des
    adresses ips pour les interfaces.
    $3 (confbrs) est le nom d'un tableau contenant la configuration des
    bridges à créer/mettre à jour.
    $4 (mainiface) est le nom de l'interface principale, c'est à dire
    l'interface qui est sélectionnée si une adresse ip n'est pas préfixée de
    son interface. En principe, l'interface principale est le premier bridge
    défini ou la première interface définie.
    $5 (reset_interfaces) spécifie de ne pas chercher à mettre à jour le
    fichier /etc/network/interfaces, mais de le recréer depuis zéro.
    $6 (oldhost) est le nom d'hôte actuel, avant la modification
    Si un des arguments n'est pas spécifié, il est ignoré.
    Le tableau confips doit contenir des définitions d'une des formes
    suivantes:
    [[iface][//gateway]:]address[/suffix],...
    [iface:]dhcp
    La deuxième forme est pour spécifier qu'une interface est configurée par
    DHCP. iface vaut par défaut eth0, sauf si une définition de bridge
    existe, auquel cas il s'agit du premier bridge défini. Pour chaque
    interface, seule la première spécification d'adresse IP tient compte de
    l'argument gateway. Les autres spécifications définissent des adresses IP
    supplémentaires pour l'interface.
    Le tableau brs doit contenir des définitions de la forme suivante:
    br:ifaces,...
    br est le nom du bridge, e.g. br0. ifaces est une liste d'interfaces
    séparées par une virgule. e.g. br0:eth0,eth1
    Bien que ce soit techniquement possible, ce script interdit que l'on
    définisse une adresse IP pour une interface faisant partie d'un bridge.
    }}}

    !! {{{ensure_exists}}}
    {{{
    Créer le fichier vide "$1" s'il n'existe pas déjà, avec les permissions
    $2(=644). retourner vrai si le fichier a été créé sans erreur
    }}}
    !! {{{copy_replace}}}
    {{{
    Copier de façon inconditionnelle le fichier $1 vers le fichier $2, en
    réinitialisation les permissions à la valeur $3
    }}}
    !! {{{copy_new}}}
    {{{
    Copier le fichier "$1" vers le fichier "$2", avec les permissions $3(=644)
    Ne pas écraser le fichier destination s'il existe déjà
    Retourner vrai si le fichier a été copié sans erreur
    }}}
    !! {{{copy_update}}}
    {{{
    Copier le fichier "$1" vers le fichier "$2", si $2 n'existe pas, ou si $1
    a été modifié par rapport à $2. Réinitialiser le cas échéant les
    permissions à la valeur $3
    Retourner vrai si le fichier a été copié sans erreur.
    }}}
    !! {{{copy_update_ask}}}
    {{{
    Copier ou mettre à jour le fichier $1 vers le fichier $2.
    Si le fichier existe déjà, la différence est affichée, et une confirmation
    est demandée pour l'écrasement du fichier.
    Retourner vrai si le fichier a été copié sans erreur.
    }}}
    !! {{{copy_tree}}}
    {{{
    Copier de façon inconditionnelle l'arborescence $1 dans l'arborescence $2
    }}}
    !! {{{link_new}}}
    {{{
    Si $2 n'existe pas, créer le lien symbolique $2 pointant vers $1
    }}}

    !! {{{get_random_kvm_macaddr}}}
    {{{
    Obtenir une adresse mac au hasard commençant par 52:54:00 pour KVM
    }}}
    !! {{{ipcalc_splitipmask}}}
    {{{
    Découper $1 de la forme ip[/mask] entre l'adresse ip, qui est placé dans
    la variable $2(=ip) et le masque, qui est placée dans la variable
    $3(=mask)
    }}}
    !! {{{ipcalc_checkip}}}
    {{{
    Vérifier l'adresse ip $1 pour voir si elle est valide. Si l'adresse est
    valide, l'afficher. Sinon, retourner 1
    }}}
    !! {{{ipcalc_checkmask}}}
    {{{
    vérifier le masque de sous-réseau $1 pour voir si elle est valide. Si oui,
    afficher le suffixe (0, 8, 16, 24, 32) associé. Sinon retourner 1
    }}}
    !! {{{ipcalc_netmask}}}
    {{{
    à partir d'un suffixe (0, 8, 16, 24, 32) ou d'un masque de sous-réseau,
    afficher le masque de sous-réseau. si le suffixe ou le masque ne sont pas
    reconnus, retourner 1
    }}}
    !! {{{ipcalc_broadcast}}}
    {{{
    Calculer l'adresse de broadcast correspondant à l'adresse ip $1. Le masque
    de sous-réseau peut-être indiqué dans l'adresse ip avec le suffixe /n ou
    /x.x.x.x ou donné dans l'argument $2. Seuls les suffixes 0, 8, 16, 24, 32
    sont supportés.
    Retourner 1 si un erreur s'est produite, par exemple si l'adresse ou le
    suffixe sont invalides ou non supportés.
    }}}
    !! {{{ipcalc_gateway}}}
    {{{
    Calculer l'adresse du gateway correspondant à l'adresse ip $1, en
    considérant que le gateway est la première adresse du réseau. Le masque de
    sous-réseau peut-être indiqué dans l'adresse ip avec le suffixe /n ou
    /x.x.x.x ou donné dans l'argument $2. Seuls les suffixes 0, 8, 16, 24, 32
    sont supportés.
    Retourner 1 si un erreur s'est produite, par exemple si l'adresse ou le
    suffixe sont invalides ou non supportés.
    }}}
    !! {{{ipcalc_match}}}
    {{{
    Vérifier si l'adresse $1 correspond au modèle $2, e.g.:
    ipcalc_match 10.75.0.23 10/8         --> TRUE
    ipcalc_match 10.75.0.23 10.75.0.0/24 --> TRUE
    ipcalc_match 10.75.0.23 10.75.0.28   --> FALSE
    }}}
    !! {{{ipcalc_fqdn}}}
    {{{
    Calculer si possible le nom pleinement qualifié correspondant à l'hôte $1.
    Dans tous les cas, afficher l'hôte, mais retourner 1 si la calcul n'a pas
    pu être effectué.
    }}}
    !! {{{ipcalc_fqdn_maybe}}}
    {{{
    Si $1 *semble* déjà être un nom d'hôte pleinement qualifié, l'afficher tel
    quel. Sinon utiliser ipcalc_fqdn() pour afficher le nom d'hôte pleinement
    qualifié correspondant.
    }}}

    !! {{{select_java}}}
    {{{
    sélectionner la version *minimum* de java correspondant à $1
    $1== 1.3|1.3+|1.4|1.4+|1.5|1.5+|1.6|1.6+|1.7|1.7+|1.8|1.8+
    Si $2 est défini, il peut s'agit de 32 ou 64 selon que l'on requière la
    version 32bits ou 64 bits
    }}}
    !! {{{select_java_exact}}}
    {{{
    sélectionner la version *exacte* de java correspondant à $1
    $1== 1.3|1.4|1.5|1.6|1.7|1.8 pour une correspondance exacte
    $1== 1.3+|1.4+|1.5+|1.6+|1.7+|1.8+ pour une version minimum
    Si $2 est défini, il peut s'agit de 32 ou 64 selon que l'on requière la
    version 32bits ou 64 bits
    }}}
    !! {{{select_java_any}}}
    {{{
    Sélectionner la version exacte de java correspondant aux arguments, dans
    l'ordre, jusqu'à ce qu'un argument corresponde. DEFAULT correspond à la
    valeur actuelle de JAVA_HOME, si elle est définie.
    Si aucun argument n'est défini, on assume "DEFAULT 5 6 7 8 1.4"
    }}}
    !! {{{get_java_version}}}
    {{{
    Afficher la version de java qui installée dans $1(=$JAVA_HOME)
    En cas d'erreur, ne rien afficher.
    }}}
    !! {{{get_default_javahome_prefix}}}
    !! {{{get_javaextensions_prefix}}}
    !! {{{compute_java_prefixes}}}
    !! {{{recompute_java_prefixes}}}
    !! {{{get_JAVA_HOME_prefix}}}
    !! {{{get_JAVAEXTENSIONS_prefix}}}

    !! {{{read_property}}}
    {{{
    Lire la propriété $2 dans le fichier $1, et placer la valeur dans la
    variable $3. Si la propriété n'existe pas, prendre la valeur par défaut
    $4. Si $3=="", elle est construite à partir de $2 en remplaçant les '.'
    par '_'
    Retourner 1 si une erreur s'est produite (par exemple si le fichier
    n'existe pas ou n'est pas accessible en lecture)
    }}}
    !! {{{write_property}}}
    {{{
    Ecrire la propriété $2 dans le fichier $1 avec la valeur $3.
    Retourner 1 si une erreur s'est produite (par exemple si le fichier
    n'existe pas ou n'est pas accessible en écriture)
    }}}
    !! {{{write_properties}}}
    {{{
    Ecrire les propriétés $2..* dans le fichier $1. Les propriétés sont de la
    forme "name=value"
    }}}
    !! {{{norm_properties}}}
    {{{
    Normaliser un fichier de propriété: Les commentaires sont supprimés, les
    valeurs sont triées par ordre alphabétique, les caractères accentués sont
    remplacés par des caractères unicode \\uxxxx, les séquences unicodes sont
    transformées en minuscule.
    }}}

    !! {{{json_filter}}}
    {{{
    traiter un flux json pour que chaque valeur soit sur une ligne séparée,
    facilitant le traitement par un script bash
    }}}
    !! {{{awkjson}}}

    !! {{{get_default_ldapconfdir_prefix}}}
    {{{
    Calculer et afficher la valeur par défaut de LDAPCONFDIR, ou une chaine
    vide si l'on n'a pas pu le détecter automatiquement.
    }}}
    !! {{{get_default_ldapowner_prefix}}}
    {{{
    Calculer et afficher la valeur par défaut de LDAPOWNER, ou une chaine
    vide si l'on n'a pas pu le détecter automatiquement.
    }}}
    !! {{{compute_ldap_prefixes}}}
    !! {{{recompute_ldap_prefixes}}}
    !! {{{get_LDAPCONFDIR_prefix}}}
    !! {{{get_LDAPOWNER_prefix}}}
    !! {{{split_ldapuri}}}
    {{{
    spliter le ldapuri $1 en $2(=proto), $3(=host) et $4(=port)
    }}}
    !! {{{get_suffixes}}}
    {{{
    obtenir les suffixes de connexion du serveur avec l'uri $1, un par ligne
    retourner 1 si la valeur n'a pas pu être obtenue
    }}}
    !! {{{get_anysuffix}}}
    {{{
    obtenir le *premier* suffixe du serveur avec l'uri $1
    retourner 1 si la valeur n'a pas pu être obtenue
    }}}
    !! {{{get_dcsuffix}}}
    {{{
    obtenir le *premier* suffixe du serveur avec l'uri $1 qui se termine par
    dc=TLD où TLD est une valeur quelconque. A priori, c'est un suffixe d'une
    base de donnée non administrative.
    retourner 1 si la valeur n'a pas pu être obtenue
    }}}
    !! {{{get_suffix}}}
    {{{
    obtenir le *premier* suffixe du serveur avec l'uri $1 qui se termine si
    possible par dc=TLD où TLD est une valeur quelconque. Dans le cas normal,
    le suffixe affiché est celui d'une base non administrative.
    retourner 1 si la valeur n'a pas pu être obtenue
    }}}
    !! {{{reldn}}}
    !! {{{absdn}}}
    {{{
    obtenir le dn absolu correspondant au dn $1, le dn de base étant
    $2(=$SUFFIX)
    }}}
    !! {{{subof}}}
    {{{
    tester si le dn absolu $1 est $2 ou un enfant de $2
    }}}
    !! {{{rabsdn}}}
    {{{
    comme absdn, mais tient compte de la valeur de $3(=$SEARCHBASE)
    Si le dn commence par "~/", le dn est relatif à $2(=$SUFFIX)
    Si le dn commence par "/", le dn est absolu
    Sinon, le dn est relatif à $3
    }}}
    !! {{{pdn}}}
    {{{
    corriger pour *affichage* un dn *absolu*. pour la racine "", afficher
    '/'. pour $2(=$SUFFIX), afficher '~'. sinon, afficher le dn relativement à
    $2
    }}}
    !! {{{filter_slapdconf}}}
    {{{
    Traiter un fichier de configuration slapd.conf en fusionnant les lignes
    qui sont découpées. Ceci permet de faire des traitements sur le contenu.
    Ce filtre s'utilisera normalement avec filter_conf, e.g.:
    <slapd.conf filter_slapdconf | filter_conf >result.conf
    }}}

    !! {{{def_match_attr}}}
    !! {{{def_match_value}}}
    !! {{{uncut_lines}}}
    {{{
    reformer les lignes qui sont coupées
    }}}
    !! {{{cut_lines}}}
    {{{
    couper les lignes trop longues
    }}}
    !! {{{ensure_complete_objects}}}
    {{{
    S'assurer que le ldif ne contient que des objets complets (éliminant ainsi
    les groupes ayant seulement dn:)
    }}}
    !! {{{delete_marked_objects}}}
    {{{
    Supprimer les objets marqués avec --DELETE--:
    }}}
    !! {{{dump_ldif}}}
    !! {{{tl_addattr}}}
    !! {{{tl_modifyattr}}}
    !! {{{tl_deleteattr}}}
    !! {{{tl_deleteentry}}}
    !! {{{tl_touchentry}}}
    !! {{{tl_keepattr}}}
    !! {{{tl_keepval}}}
    !! {{{tl_excludeattr}}}
    !! {{{tl_excludeval}}}
    !! {{{tl_keepvalentry}}}
    !! {{{tl_excludevalentry}}}
    !! {{{tl_replval}}}
    !! {{{tl_addval}}}
    !! {{{tl_defval}}}
    !! {{{print_values}}}
    !! {{{tl_ensureval}}}
    !! {{{print_ensure_values}}}
    !! {{{tl_decode}}}
    !! {{{tl_encode}}}
    !! {{{tl_format}}}
    !! {{{dump_headers}}}
    !! {{{tl_formatcsv}}}
    !! {{{tl_parsecsv}}}
    !! {{{tl_parsecsvmod}}}
    !! {{{get_transform_cmd}}}
    {{{
    Créer une liste de commandes bash à évaluer en fonction des arguments: une
    suite de commandes séparées par //
    Les variables suivantes peuvent être définies en entrée:
    _T_inputfile:
    Si cette variable est non vide, lire à partir du fichier $_T_inputfile
    au lieu de stdin
    _T_uncut_before:
    faut-il fusionner automatiquement les lignes *avant* de lancer les
    commandes.
    _T_cut_after:
    faut-il découper automatiquement les lignes *après* avoir lancé les
    commandes.
    }}}
    !! {{{transform}}}

    !! {{{file_get_vars}}}
    {{{
    lire les variables dans un fichier
    }}}
    !! {{{file_set_vars}}}
    {{{
    écrire les variables dans un fichier. Le fichier *doit exister*
    }}}
    !! {{{write_all_remaining_vars}}}
    !! {{{file_get_properties}}}
    {{{
    lire les propriétés d'un fichier de propriété java ou xml
    }}}
    !! {{{file_set_properties}}}
    {{{
    écrire les propriétés d'un fichier de propriété java ou xml
    }}}
    !! {{{file_get_java_properties}}}
    {{{
    lire les propriétés d'un fichier de propriétés java. note: les noms de
    propriété java peuvent contenir le caractère "." mais pas les noms de
    variable bash. La conversion est faite automatiquement. Par exemple::
    file_get_properties build.properties path.to.package "default value"
    charge la valeur de la propriété dans la variable path_to_package
    }}}
    !! {{{file_set_java_properties}}}
    {{{
    écrire des propriétés dans un fichier de propriétés java.
    }}}
    !! {{{write_all_remaining_vars}}}
    !! {{{file_get_xml_properties}}}
    {{{
    lire les propriétés d'un fichier de propriétés xml. Limitation: les
    propriétés ne doivent pas être continuées sur plusieurs lignes. Les
    propriétés doivent être écrites sous la forme::
    <propname>propvalue</propname>
    }}}
    !! {{{file_set_xml_properties}}}
    {{{
    écrire des propriétés dans un fichier de propriétés java.
    }}}
    !! {{{write_all_remaining_vars}}}

    !! {{{local_shellfix}}}
    {{{
    Modifier le compte local $1 pour qu'il utilise bash au lieu de sh
    }}}
    !! {{{local_usercheck}}}
    {{{
    Vérifier si le user local $1 existe
    }}}
    !! {{{local_useradd}}}
    {{{
    Créer le user local $1
    USAGE: local_useradd username [gecos [passwd]]
    OPTIONS
    -s  Créer l'utilisateur avec les droits d'administrateur
    -m  Créer le home directory
    }}}

    !! {{{mkcrypt}}}

    !! {{{printml}}}
    !! {{{addml}}}

    !! {{{SERVICE_OVERRIDE_network_manager_stopx}}}
    {{{
    désactiver network-manager avant de l'arrêter, ce qui permet de s'assurer
    que chaque chaque connexion est arrêtée proprement
    }}}
    !! {{{SERVICE_OVERRIDE_network_manager_startx}}}
    {{{
    cette fonction est le pendant de stopx: penser à relancer network-manager
    après avoir démarré le service
    }}}

    !! {{{random_index}}}
    {{{
    Afficher un index au hasard dans le tableau $1
    }}}
    !! {{{random_value}}}
    {{{
    Afficher une valeur au hasard dans le tableau $1
    }}}
    !! {{{random_char}}}
    {{{
    Afficher un caractère au hasard dans la chaine $1
    }}}
    !! {{{genpass}}}
    {{{
    Générer un mot de passe au hasard avec les paramètres GENPASS_*
    }}}

    !! {{{pkg_check}}}
    {{{
    Vérifier que les packages sont installés sur le système
    Retourner 123 si le système n'est pas supporté, et donc qu'aucune commande
    d'installation de package n'est disponible.
    }}}
    !! {{{pkg_install}}}
    {{{
    Installer les packages sans confirmation
    Retourner 123 si le système n'est pas supporté, et donc qu'aucune commande
    d'installation de package n'est disponible.
    }}}

    !! {{{get_USER_prefix}}}
    !! {{{get_HOME_prefix}}}
    !! {{{has_prefix}}}
    !! {{{expand_prefix}}}
    !! {{{list_prefixes}}}
    !! {{{dump_prefixes}}}

    !! {{{get_color}}}
    !! {{{set_verbosity}}}
    !! {{{set_interaction}}}
    !! {{{show_error}}}
    !! {{{show_warn}}}
    !! {{{show_info}}}
    !! {{{show_verbose}}}
    !! {{{show_debug}}}
    !! {{{check_verbosity}}}
    !! {{{get_verbosity_option}}}
    !! {{{check_interaction}}}
    !! {{{is_interaction}}}
    !! {{{get_interaction_option}}}

    !! {{{is_any_branch}}}
    !! {{{is_master_branch}}}
    !! {{{is_develop_branch}}}
    !! {{{is_release_branch}}}
    !! {{{is_hotfix_branch}}}
    !! {{{is_feature_branch}}}
    !! {{{list_release_branches}}}
    !! {{{list_hotfix_branches}}}
    !! {{{list_feature_branches}}}
    !! {{{pver}}}

    !! {{{pkg_check}}}
    {{{
    Vérifier que les packages sont installés sur le système
    }}}
    !! {{{pkg_update}}}
    {{{
    Mettre à jour la liste des packages silencieusement sans confirmation
    }}}
    !! {{{pkg_upgrade}}}
    {{{
    Mettre à jour la liste des packages silencieusement sans confirmation
    }}}
    !! {{{pkg_install}}}
    {{{
    Installer les packages silencieusement et sans confirmation
    }}}
    !! {{{pkg_installm}}}
    {{{
    Installer les packages silencieusement et sans confirmation
    Retourner 0 si au moins un des packages a été installé. Sinon, les
    packages n'ont pas été instllés, soit parce qu'ils sont déjà installé,
    soit parce qu'il y a eu une erreur.
    }}}
    !! {{{service_disable}}}
    {{{
    Désactiver le service $1 pour qu'il ne se lance pas automatiquement au
    démarrage
    }}}
    !! {{{service_enable}}}
    {{{
    Activer le service $1 pour qu'il se lance automatiquement au démarrage
    }}}
    !! {{{create_bridge}}}
    {{{
    Créer un nouveau pont nommé $1 avec les paramètres $2
    }}}

    !! {{{runs_initdir}}}
    {{{
    Initialiser le répertoire d'hôte. $1 est un nom d'hôte pleinement
    qualifié, et les fichiers sont créés dans le premier répertoire de
    RUNSHOSTSDIRS qui convient: si un fichier .udir existe avec un tableau
    runs_domains qui contient le domaine de l'hôte spécifié, alors c'est ce
    répertoire qui est sélectionné. Sinon, on prend le premier répertoire de
    RUNSHOSTSDIRS.
    $2 spécifie si le fichier doit être créé avec de l'aide (yes) ou avec le
    script minimum (no)
    $3 est le contenu à placer dans le fichier sysinfos.conf, s'il n'a pas
    déjà été provisionné.
    Il faut lancer __runs_setpath avant d'utiliser cette fonction et
    RUNSHOSTDIRS ne doit pas être vide
    }}}
    !! {{{runs_create_rscript}}}
    {{{
    Créer un modèle de script. Si $2 est spécifié, c'est un nom d'hôte
    pleinement qualifié. Le répertoire d'hôte correspondant *doit* exister.
    $3 spécifie si le fichier doit être créé avec de l'aide (yes) ou avec le
    script minimum (no)
    Si $2!="", il faut lancer __runs_setpath avant d'utiliser cette fonction
    et RUNSHOSTDIRS ne doit pas être vide
    Le chemin du nouveau script est ajouté au tableau new_rscripts
    }}}
    !! {{{runs_unsupported_system}}}
    {{{
    Afficher un message d'erreur indiquant que le système actuel n'est pas
    supporté, et quitter le script
    }}}
    !! {{{runs_require_sysinfos}}}
    {{{
    Vérifier le système actuel avec check_sysinfos(), et afficher un message
    d'erreur avec runs_unsupported_system() s'il ne correspond pas à la
    requête
    }}}
    !! {{{runs_find_host}}}
    !! {{{runs_add_domain}}}
    {{{
    Si $1 est nom d'hôte pleinement qualifié, retourner cette valeur
    Sinon, lui rajouter le domaine RUNSDOMAIN
    }}}
    !! {{{runs_find_hostfile}}}
    {{{
    Trouver et afficher le fichier d'hôte $1 dans les répertoires du tableau
    $3(=RUNSHOSTSDIRS), pour l'hôte $2(=$RUNSHOST). Retourner 0 en cas de
    succès, 1 en cas d'échec.
    Si host=$2 est une valeur non vide, la recherche est effectuée dans
    {$RUNSHOSTSDIRS}/$host et {$RUNSHOSTSDIRS}/$domain/$hostname. Sinon,
    retourner 1, car il faut spécifier un nom d'hôte.
    }}}
    !! {{{runs_find_datafile}}}
    {{{
    Trouver et afficher le fichier de données $1 dans le répertoire $3 s'il
    est non vide puis dans les répertoires des tableaux $4(=RUNSSCRIPTSDIRS),
    $5(=RUNSMODULESDIRS) et $6(=RUNSHOSTSDIRS), pour l'hôte
    $2(=$RUNSHOST). Retourner 0 en cas de succès, 1 en cas d'échec.
    - D'abord, si $1 *n'est pas* de la forme "./path" ou "../path", chercher
    dans $3.
    - Puis si l'hôte est spécifié, chercher dans {$RUNSHOSTSDIRS}/$host et
    {$RUNSHOSTSDIRS}/$domain/$hostname.
    - Puis chercher dans {$RUNSSCRIPTSDIRS} puis {$RUNSMODULESDIRS}.
    - Puis, si $1 est de la forme "./path" ou "../path", chercher dans $3.
    - Sinon, retourner 1
    }}}
    !! {{{runs_initvars}}}
    {{{
    Initialiser les variables RUNSDIR, RUNSSCRIPT, RUNSDIRPATH,
    RUNSSCRIPTPATH, RUNSSCRIPTDIR et RUNSSCRIPTNAME pour le script $1.
    Les valeurs sont initialisées comme suit:
    RUNSSCRIPT="$(abspath "$1")"
    RUNSDIR="$2" (le répertoire de $RUNS*PATH dans lequel a été trouvé le
    script)
    Si $3!="", RUNSDIRPATH="$3" et RUNSSCRIPTPATH="$4"
    Sinon, RUNSDIRPATH="$RUNSSCRIPTDIR" et RUNSSCRIPTPATH="$RUNSSCRIPTNAME"
    }}}
    !! {{{runs_find_scriptfile}}}
    {{{
    Trouver sans l'afficher le script $1 dans les répertoires des tableaux
    $3(=RUNSSCRIPTSDIRS), $4(=RUNSMODULESDIRS) et $5(=RUNSHOSTSDIRS), en
    considérant que le script sera lancé sur l'hôte $2(=$RUNSHOST), et
    initialiser les variables RUNSDIR, RUNSSCRIPT, RUNSSCRIPTDIR,
    RUNSSCRIPTNAME, RUNSDIRPATH et RUNSSCRIPTPATH. Retourner 0 en cas de
    succès, 1 en cas d'échec.
    $6 vaut ".rs" par défaut est c'est une extension à rajouter au nom
    spécifié si le fichier sans l'extension n'existe pas
    RUNSDIR est le répertoire dans lequel a été trouvé le script (parmi les
    valeurs fournies dans les tableaux RUNSSCRIPTSDIRS, RUNSMODULESDIRS,
    RUNSHOSTSDIRS), RUNSDIRPATH est le répertoire à partir duquel est exprimé
    le chemin du script (i.e RUNSDIRPATH + RUNSSCRIPTPATH == RUNSSCRIPT),
    RUNSSCRIPT contient le chemin absolu vers le script, RUNSSCRIPTPATH
    contient le chemin du script dans RUNSDIRPATH, RUNSSCRIPTDIR le répertoire
    du script, et RUNSSCRIPTNAME le nom du script.
    D'abord, si l'hôte est spécifié, chercher dans {$RUNSHOSTSDIRS}/$host et
    {$RUNSHOSTSDIRS}/$domain/$hostname. Puis chercher dans {$RUNSSCRIPTSDIRS}
    }}}
    !! {{{runs_find_scriptfile_reverse}}}
    {{{
    Soit le fichier de script $1, exprimée de façon absolue, trouver le
    fichier parmi les tableaux $3(=RUNSSCRIPTSDIRS), $4(=RUNSMODULESDIRS)
    et $5(=RUNSHOSTSDIRS), en considérant que le script sera lancé sur l'hôte
    $2(=$RUNSHOST), puis initialiser les variables RUNSDIR, RUNSSCRIPT,
    RUNSSCRIPTDIR, RUNSSCRIPTNAME, RUNSDIRPATH et RUNSSCRIPTPATH. Retourner 0
    en cas de succès, 1 en cas d'échec.
    }}}
    !! {{{runs_rscript}}}
    {{{
    Lancer le fichier $1 comme un script avec les arguments $2..$*. Retourner
    la valeur de retour du script.
    }}}
    !! {{{runs_recipe}}}
    {{{
    Lancer les scripts de la recette contenue dans le fichier $1. Arrêter au
    premier script qui est en erreur
    }}}
    !! {{{runs_rscriptpath}}}
    {{{
    Lancer le script $1 avec les arguments $2..$*. Le script est cherché dans
    les répertoires de RUNSSCRIPTSPATH. Retourner 123 si le script n'est pas
    trouvé, sinon retourner la valeur de retour du script.
    }}}
    !! {{{runs_recipepath}}}
    {{{
    Lancer la recette $1. Le fichier de recette est cherché dans les
    répertoires de RUNSSCRIPTSPATH. Retourner 123 si le fichier de recette n'a
    pas été trouvé, sinon retourner la valeur de retour de runs_recipe()
    }}}
    !! {{{runs_init}}}
    !! {{{runs_initdomains}}}
    {{{
    Si ce n'est pas déjà le cas, initialiser RUNSDOMAINS en fonction de
    /etc/resolv.conf
    }}}
    !! {{{runs_inithost}}}
    !! {{{runs_initsysinfos}}}
    !! {{{runs_initworkdir}}}
    !! {{{runs_after_export}}}
    {{{
    après l'export, initialiser varsfile avec les valeurs qu'il faut garder
    entre le déploiement local et le déploiement distant.
    }}}
    !! {{{runs_check_runsscript}}}
    !! {{{runs_var}}}
    {{{
    Initialiser les variables selon les directives données en ligne de
    commande.
    Les arguments peuvent être une suite de définitions de la forme
    'scalar=value', 'scalar!=name', 'array+=value', 'array-=value' ou
    'array@=name'.
    Sinon, le *dernier* argument peut-être de l'une des formes suivantes:
    'array value0 [value1...]' pour initialiser un tableau,
    'array+ value0 [value1...]' pour ajouter des valeurs à un tableau,
    'array- value0 [value1...]' pour enlever des valeurs à un tableau.
    Les formes 'scalar!=value' et 'array@=value' sont des indirections et
    permettent d'initialiser la variable avec la valeur d'une autre
    variable. L'avantage est que la résolution de la valeur est faite
    uniquement lors de l'appel de cette fonction, ce qui est utile avec des
    fonction comme 'after -r'
    }}}
    !! {{{runs_conf}}}
    {{{
    Activer les flags $*
    }}}
    !! {{{runs_indref}}}
    {{{
    fonction de convenance pour créer des références $3..* avec le fichier de
    configuration $1 et les variables $2
    }}}
    !! {{{runs_refcerts}}}
    {{{
    fonction de convenance pour créer une référence à un répertoire contenant
    des certificats mentionnés dans le fichier de configuration $1. Si les
    références $2..* ne sont pas mentionnées, la variable certsdir dans le
    fichier de configuration est utilisée.
    }}}
    !! {{{runs_refapacheconfig}}}
    {{{
    fonction de convenance pour créer les références à un répertoire de
    configuration pour apache.
    USAGE: refapacheconfig autoconfdir=path/to/autoconfdir [certsdir=[path/to/certsdir]]
    - autoconfdir= est requis et permet de définir à la fois la variable qui
    contiendra la référence ainsi que le répertoire à référencer.
    - certsdir= est optionel. Si cet argument est spécifié sous la forme
    certsdir=path/to/certsdir, il permet de définir à la fois la variable qui
    contiendra la référence ainsi que le répertoire à référencer. Si
    l'argument est spécifié sous la forme certsdir=, il permet de définir la
    variable qui contiendra la référence. C'est cette variable qui sera lue
    dans les fichiers de configuration. Si l'argument n'est pas spécifié, on
    considère que l'argument 'certsdir=' a été utilisé.
    }}}
    !! {{{runs_set_lang}}}
    {{{
    Charger la valeur de LANG depuis l'environnement. La variable LANG est
    initialisée
    }}}
    !! {{{runs_set_proxy}}}
    {{{
    Charger la valeur du proxy depuis l'environnement. Les variables
    http_proxy, ftp_proxy et no_proxy sont initialisées
    }}}
    !! {{{runs_check_confs}}}
    {{{
    Vérifier l'état courant par rapport aux flags
    }}}
    !! {{{runs_after}}}
    {{{
    Vérifier que ce script est lancé après le scriptpath $1, par rapport à
    RUNSSTORY
    }}}
    !! {{{runs_clvars}}}
    {{{
    Traiter les spécifications de variables données en ligne de commande ou
    dans un fichier de recettes
    }}}
    !! {{{runs_indvars}}}
    {{{
    Résoudre les valeurs effectives des variables qui sont des indirections
    }}}
    !! {{{runs_clvars_cmd}}}
    {{{
    écrire la ligne de recette correspondant au script $1 et aux variables
    $2..$*
    }}}
    !! {{{runs_loadconfs}}}
    !! {{{runs_clearvars}}}
    !! {{{runs_action_desc}}}
    !! {{{runs_action_dump}}}
    !! {{{runs_action_run}}}
    !! {{{runs_action_export}}}
    !! {{{shouldrun}}}
    !! {{{checkdone}}}
    !! {{{requiredone}}}
    !! {{{setdone}}}
    !! {{{resetdone}}}

    !! {{{runsmod_checkenv}}}
    {{{
    vérifier l'environement. créer les répertoires nécessaires.
    }}}
    !! {{{runsmod_should_update_repolists}}}
    {{{
    tester s'il faut mettre à jour au moins un des fichiers contenant les
    listes des dépôts
    }}}
    !! {{{runsmod_update_repolists}}}
    {{{
    mettre à jour si nécessaire les fichiers contenant les listes des dépôts.
    Si $1 n'est pas vide, forcer la mise à jour de tous les fichiers
    }}}
    !! {{{runsmod_setup_vars}}}
    {{{
    récupérer configuration statique pour la mettre à jour
    }}}
    !! {{{runsmod_clone_or_pull}}}
    {{{
    Chercher les modules $3..@, pour l'hôte $1 qui est le mode d'hôte: none,
    all, self ou one pour un hôte spécifique $2. Ajouter les chemins dans le
    tableau REPO_DIRS. Mettre à jour les tableaux SCRIPTS_DIRS, MODULES_DIRS
    et HOSTS_DIRS
    }}}
    !! {{{runsmod_teardown_vars}}}

    !! {{{semver_parse}}}
    !! {{{semver_incmajor}}}
    !! {{{semver_incminor}}}
    !! {{{semver_incpatchlevel}}}
    !! {{{semver_setversion}}}
    !! {{{semver_setprelease}}}
    !! {{{semver_compare_prelease}}}
    !! {{{semver_setmetadata}}}
    !! {{{semver_addmetadata}}}
    !! {{{semver_compare_metadata}}}
    {{{
    même algo que pour prelease
    }}}
    !! {{{semver_copy}}}
    !! {{{semver_build}}}
    !! {{{semver_setvar}}}
    !! {{{psemver_parse}}}
    !! {{{psemver_incmajor}}}
    !! {{{psemver_incminor}}}
    !! {{{psemver_incpatchlevel}}}
    !! {{{psemver_setversion}}}
    !! {{{psemver_setprelease}}}
    !! {{{psemver_compare_prelease}}}
    !! {{{psemver_setmetadata}}}
    !! {{{psemver_addmetadata}}}
    !! {{{psemver_compare_metadata}}}
    !! {{{psemver_copy}}}
    !! {{{psemver_build}}}
    !! {{{psemver_setvar}}}

    !! {{{service}}}
    !! {{{service_start}}}
    {{{
    démarrer le service $1 de façon inconditionnelle
    }}}
    !! {{{service_startm}}}
    {{{
    démarrer le service $1 s'il n'est pas déjà démarré
    }}}
    !! {{{service_stop}}}
    {{{
    arrêter le service $1 de façon inconditionnelle
    }}}
    !! {{{service_stopm}}}
    {{{
    arrêter le service $1 s'il n'est pas déjà arrêté
    }}}
    !! {{{service_reload}}}
    {{{
    recharger le service $1
    }}}
    !! {{{service_status}}}
    {{{
    tester/afficher le status du service $1
    }}}

    !! {{{read_data}}}
    !! {{{dump_data}}}
    !! {{{compute_local_sysinfos}}}
    !! {{{compute_remote_sysinfos}}}
    !! {{{ensure_sysinfos}}}
    {{{
    Essayer de déterminer les valeurs des variables $1(=SYSNAME), $2(=SYSDIST)
    et $3(=SYSVER) en fonction des valeurs des autres. Cette fonction est à
    utiliser quand on récupère cette information de la part de l'utilisateur,
    et qu'il faut compléter
    }}}
    !! {{{get_sysinfos_desc}}}
    {{{
    Afficher une chaine de la forme SYSNAME/SYSDIST/SYSVER qui décrit le
    système actuel
    }}}
    !! {{{check_sysinfos}}}
    {{{
    Tester si le système courant ($MYSYSNAME, $MYSYSDIST, $MYSYSVER, $MYBITS)
    correspond à au moins un des arguments.
    Il est possible de spécifier des variables différentes pour tester le
    système courant avec l'option --vars qui doit être spécifiée en premier:
    check_sysinfos --vars sysname sysdist sysver bits -d debian
    Les options -s, -d, -v, -b permettent respectivement de vérifier le
    système, la distribution, la version et le nombre de bits. Il est possible
    de spécifier plusieurs tests à effectuer, e.g.:
    check_sysinfos -d debian ubuntu -b 64
    pour tester si l'on est sur une distribution debian ou ubuntu *et* sur un
    système 64 bits
    Note: avec l'option --vars, il peut arriver que sysname, sysdist ou sysver
    ne soient pas des tableaux mais des variables scalaires, surtout si elles
    sont fournies par l'utilisateur. Il est conseillé dans ce cas de tester
    toutes les possibilités quand on vérifie une valeur, e.g.:
    check_sysinfos --vars sysname sysdist sysver bits -s linux64 linux32 linux
    pour tester si on est sur un système linux
    Avec l'option -v, il est possible de suffixer la valeur avec + ou - selon
    que l'on veut toutes les versions situées après ou avant la version
    spécifiée. Attention, à cause d'une limitation de l'implémentation, il
    faut alors impérativement filtrer aussi sur la distribution, e.g:
    check_sysinfo -d debian -v lenny+
    pour tester si on est en lenny ou en squeeze.
    De même, l'option -d accepte aussi de suffixer la valeur avec + ou -, mais
    cela n'a actuellement de sens qu'avec les version de MacOS X. Il faut
    aussi impérativement filtrer sur le système, e.g:
    check_sysinfos -s macosx -d 10.5+
    }}}
    !! {{{on_debian}}}
    {{{
    Tester si on est sur debian. charger le module debian si c'est le cas.
    Si une commande $1..@ est spécifiée, la lancer, mais il n'est alors plus
    possible de lancer des tests plus spécifiques avec __on_debian()
    }}}
    !! {{{on_debian:}}}
    !! {{{on_stretch}}}
    !! {{{on_jessie}}}
    !! {{{on_wheezy}}}
    !! {{{on_squeeze}}}
    !! {{{on_default}}}

    !! {{{template_list}}}
    {{{
    Soit $N le séparateur --, lister les fichiers des répertoires sources
    $2..$(N-1) qui seraient fusionnés avec template_merge() ou supprimés avec
    template_unmerge() du répertoire destination $1. Si des chemins sont spécifiés
    avec les arguments $(N+1)..@, ne traiter que les fichiers qui correspondent à
    ces spécifications. Exemple:
    template_list destdir srcdirs... -- specs...
    }}}
    !! {{{template_merge}}}
    {{{
    Soit $N le séparateur --, copier dans le répertoire destination $1 les
    fichiers des répertoires sources $2..$(N-1) correspondant aux spécifications
    $(N+1)..@, si ces fichiers n'ont pas été modifiés dans le répertoire de
    destination.
    Les fichiers sources ayant l'extension .template sont ignorés par défaut, sauf
    s'ils sonts demandés explicitement. Exemple:
    template_merge destdir srcdirs... -- specs...
    }}}
    !! {{{template_unmerge}}}
    {{{
    Soit $N le séparateur --, supprimer du répertoire destination $1 les fichiers
    provenant des répertoires sources $2..$(N-1) et qui n'ont pas été modifiés. Si
    des chemins sont spécifiés avec les arguments $(N+1)..@, ne traiter que les
    fichiers qui correspondent à ces spécifications. Exemple:
    template_unmerge destdir srcdirs... -- specs...
    }}}
    !! {{{template_cleandest}}}
    {{{
    Supprimer dans le répertoire de destination $1 tous les répertoires vides.
    Cette fonction est habituellement utilisée après template_unmerge()
    Ignorer les chemins qui contiennent .git/ et .svn/
    }}}
    !! {{{template_diff}}}
    {{{
    Afficher les différences entre les fichiers du répertoire de destination $1 et
    les fichiers des répertoires sources $2..@
    }}}
    !! {{{template_srcdir}}}
    {{{
    Obtenir le chemin vers le répertoire source de templates $1, situé dans
    ULIBDIR/templates
    }}}
    !! {{{templatectl_config}}}
    {{{
    Obtenir le chemin vers le fichier de configuration pour le répertoire $1
    Si $2==nohideconfig, utiliser le nom CONFIG.conf, sinon utiliser par défaut
    .CONFIG sauf si le fichier CONFIG.conf existe
    }}}
    !! {{{templatectl_loadvars}}}
    {{{
    Charger les valeurs des variables depuis le fichier $1
    Les variables suivantes doivent être définies:
    - Le tableau TEMPLATECTL_DEFAULTS permet de donner une valeur par défaut aux
    variables mentionnées dans TEMPLATE_STATIC_VARS. C'est une liste de valeurs
    de la forme 'name=value'
    - Le tableau TEMPLATECTL_VARS contient des variables supplémentaires
    spécifiées par l'utilisateur. C'est une liste de valeurs de la forme
    'name=value'
    - TEMPLATE_STATIC_VARS doit contenir une liste de noms de variables qui
    peuvent être remplacés dans les fichiers de template.
    - TEMPLATE_DYNAMIC_VARS contient une liste de noms de variables valides, mais
    qui ne doivent pas être remplacés, en effet, ils sont utilisés pour le
    déploiement des fichiers.
    - TEMPLATE_NOWRITE_VARS contient une liste de noms de variables qui ne
    devraient pas être écrits dans le fichier des variables, sauf si elles
    reçoivent une valeur explicite de la part de l'utilisateur. Ce tableau est
    mis à jour lors de l'analyse du tableau TEMPLATECTL_VARS
    }}}
    !! {{{templatectl_writevars}}}
    {{{
    Ecrire les variables dans le fichier $1
    }}}
    !! {{{templatectl_list_vars}}}
    {{{
    Afficher les valeurs des variables
    }}}
    !! {{{templatectl}}}
    {{{
    Fonction de haut niveau qui facilite l'utilisation des fonctions template_*
    définir la fonction __display_templatectl_help() pour l'affichage de l'aide
    - Le tableau TEMPLATECTL_SRCDIRS doit contenir la liste des répertoires
    sources pour les templates. Alternativement, il est possible de définir la
    variable TEMPLATECTL_SRCDIR s'il n'y a qu'un seul répertoire source pour le
    template
    - TEMPLATECTL_CONFIG est le nom de base du fichier à partir duquel sont
    chargées les variables et dans lequel sont écrites les variables avec
    l'option --write-vars
    Si le nom de base est CONFIG, le fichier s'appelera .CONFIG si l'option
    --hide-config est utilisée (par défaut) ou CONFIG.conf si l'option
    --no-hide-config est utilisée
    Les variables de template_loadvars() sont aussi prises en compte
    }}}

    !! {{{twget_version}}}
    {{{
    lire le numéro de version dans le fichier $1
    }}}
    !! {{{twdump_header}}}
    {{{
    lire et afficher le contenu avant-storeArea du tiddlywiki $1
    }}}
    !! {{{twdump_footer}}}
    {{{
    lire et afficher le contenu après-storeArea du tiddlywiki $1
    }}}
    !! {{{twdump_storeArea}}}
    {{{
    lire et afficher le storeArea dans le tiddlywiki $1
    }}}
    !! {{{twreplace_storeArea}}}
    {{{
    dans le tiddlywiki $1, remplacer le storeArea par le fichier $2 (par défaut, lu sur stdin)
    }}}
    !! {{{twupgrade}}}
    {{{
    mettre à jour le tiddlywiki $1 sur la base du tiddlywiki plus récent $2
    }}}
    !! {{{twdate_curtwp}}}
    {{{
    obtenir la date courante dans le format "dd/mm/YYYY HH:MM" exprimée dans
    l'heure locale
    $1 est éventuellement la date exprimée en nombre de secondes depuis
    l'epoch, exprimée dans l'heure locale
    }}}
    !! {{{twdate_tid2twp}}}
    {{{
    Transformer $1, une date de la forme "YYYYmmddHHMM" exprimée dans le
    timezone UTC en une chaine "dd/mm/YYYY HH:MM" exprimée dans l'heure locale
    Si $1 n'est pas dans le bon format, ne rien afficher
    }}}
    !! {{{twdate_curtid}}}
    {{{
    obtenir la date courante dans le format "YYYYmmddHHMM" exprimée dans le
    timezone UTC
    $1 est éventuellement la date exprimée en nombre de secondes depuis
    l'epoch, exprimée dans l'heure locale
    }}}
    !! {{{twdate_twp2tid}}}
    {{{
    Transformer $1, une date de la forme "dd/mm/YYYY HH:MM" exprimée en heure
    locale en une chaine "YYYYmmddHHMM" exprimée dans le timezone UTC
    Si $1 n'est pas dans le bon format, ne rien afficher
    }}}
    !! {{{twdump_tiddlers}}}
    {{{
    dumper les tiddlers du fichier $1 généré avec twdump_storeArea() sous
    forme d'une liste d'appel de fonction '__tiddler_data title creator
    modifier created modified tags changecount content'
    Les arguments de la fonction sont les valeurs brutes du tiddler, qui ont
    simplement été corrigées avec unquote_html()
    }}}
    !! {{{dump_tiddler}}}
    !! {{{twdump_twpage}}}
    {{{
    Dumper le contenu de la twpage $1 sous forme d'un appel à une function
    '__twpage_data title creator modifier created modified tags changecount
    content'
    Les arguments de la fonction sont les valeurs brutes de la twpage, sauf
    que le champ modified contient toujours la date de dernière modification
    du fichier.
    }}}
    !! {{{twwrite_tiddler}}}
    {{{
    Ecrire sur STDOUT le tiddler correspondant aux paramètres sont spécifiés
    sur la ligne de commande. Les arguments sont les valeurs brutes prises de
    la twpage, telles qu'elles sont générées par twdump_twpage()
    }}}
    !! {{{twcheck_twpage_modified}}}
    {{{
    Vérifier si la twpage $1 peut être écrasée par un tiddler dont la date de
    modification est $2, de format "YYYYmmddHHMM" exprimée dans le timezone
    UTC
    C'est le cas si le fichier $1 n'existe pas, ou a une date de modification
    antérieure à $2
    }}}
    !! {{{twcheck_twpage_newtwpage}}}
    {{{
    Vérifier si la twpage $1 peut être écrasée par la twpage $2
    C'est le cas si le fichier $1 n'existe pas, ou a une date de modification
    antérieure à $2
    }}}
    !! {{{twwrite_twpage}}}
    {{{
    Ecrire dans le répertoire courant le fichier correspondant au tiddler dont
    les paramètres sont spécifiés sur la ligne de commande. Les arguments sont
    les valeurs brutes prises du tiddler, telles qu'elles sont générées par
    twdump_tiddlers()
    Retourner 0 si le fichier a été écrasé, 1 s'il n'a pas été écrasé parce
    qu'il n'a pas été modifié, 2 s'il n'a pas été écrasé parce qu'il est plus
    récent.
    Si TW_VERBOSE=1, afficher un message informatif lors de l'export
    }}}
    !! {{{export_to_twpages}}}
    {{{
    Exporter tous les tiddlers du tiddlywiki $1 dans le répertoire $2
    }}}
    !! {{{import_from_twpages}}}
    {{{
    Remplacer les tiddlers du tiddlywiki $1 par les twpages du répertoire $2
    }}}

    !! {{{udir_check}}}
    {{{
    Vérifier si le fichier $1 existe
    Si $1 est un répertoire, prendre $1/.udir
    }}}
    !! {{{udir_create_maybe}}}
    {{{
    Si le fichier $1 n'existe pas, le créer comme un template .udir
    Si $1 est un répertoire, prendre $1/.udir
    }}}
    !! {{{udir_dump}}}
    {{{
    Dumper toutes les variables définies pour le fichier $1
    Si $1 est un répertoire, prendre $1/.udir
    }}}
    !! {{{udir_eval}}}
    {{{
    Evaluer la commande "$2..$*" dans le contexte des variables définies pour
    le répertoire $1. La commande est évaluée dans un sous-shell pour ne pas
    polluer l'espace de noms courant.
    }}}
    !! {{{udir_dump_all}}}
    {{{
    Dumper toutes les variables définies pour le répertoire $1 et *tous ses
    parents* jusqu'à la racine
    }}}
    !! {{{udir_eval_all}}}
    {{{
    Evaluer la commande "$2..$*" dans le contexte des variables définies pour
    le répertoire $1 et *tous ses parents* jusqu'à la racine
    }}}
    !! {{{udir_parse}}}
    {{{
    Dans le fichier $1, lire les noms des variables
    Si $1 est un répertoire, prendre $1/.udir
    Les noms des variables sont placés dans le tableau $2(=UDIR_VARS), et les noms
    des tableaux sont placés dans le tableau $3(=UDIR_ARRAYS)
    note: les regex qui sont entre "" au lieu de // le sont à cause d'un bug
    de awk sous macosx
    }}}
    !! {{{udir_update}}}
    {{{
    Dans le fichier $1, mettre à jour les variables $2..*
    Si $1 est un répertoire, prendre $1/.udir
    Chaque argument de cette fonction est de la forme name[=value]
    Si value n'est pas précisée, la variable obtient une valeur nulle
    (i.e. var=)
    Si la variable ne figure pas dans le fichier, elle est rajoutée à la fin
    du fichier.
    Cette fonction nécessite gawk.
    }}}
    !! {{{write_unseen}}}
    !! {{{udir_edit}}}

    !! {{{uenv_update_dir}}}
    {{{
    Mettre à jour l'ordre de chargement pour le répertoire $1 qui contient des
    fichiers de profil pour le shell. L'ordre dans lequel le fichiers de
    profil doivent être chargé est écrit dans le fichier $1/.source_in_order
    Si $2 est spécifié, il s'agit d'un fichier temporaire utilisé pour les
    calculs de l'ordre des chargements.
    $3(=$1) est le répertoire de destination. Si $1 est un répertoire de
    préparation temporaire, on peut spécifier grâce à $3 quel est le
    répertoire final après préparation.
    S'ils sont spécifiés, les arguments $4..* sont des répertoires contenant
    des fichiers de profils supplémentaires qu'il faut considérer aussi. Dans
    ce cas, $3 est ignoré.
    }}}
    !! {{{uenv_set_destdirs}}}
    !! {{{uenv_sourced_in}}}
    {{{
    vérifier que l'un des fichiers $2..$* est sourcé dans $1
    }}}
    !! {{{uenv_configure_profiles}}}
    !! {{{uenv_install_profiles}}}

    !! {{{uinc}}}

    !! {{{uinst}}}
    {{{
    lancer uinst en déclarant les variables locales, de façon à ne pas polluer
    l'environnement de l'appelant.
    }}}
    !! {{{uinst_nolocal}}}
    {{{
    Interface en mode ligne de commande pour uinst. Appeler cette fonction
    avec les paramètres de la ligne de commande, e.g.:
    uinst_nolocal "$@"
    }}}

    !! {{{eerror}}}
    !! {{{die}}}
    !! {{{uprovided}}}
    {{{
    Tester si le module $1 a déjà été chargé par urequire
    }}}
    !! {{{uprovide}}}
    {{{
    Spécifier que le module $1 a été sourcée, ou prétendre que c'est le cas.
    Retourner 1 si le module était déjà pourvu, 0 si c'est la première fois
    qu'on le pourvoit
    }}}
    !! {{{urequire}}}
    {{{
    Sourcer un module recherché dans ULIBDIRS
    Le module DEFAULTS est traité de façon particulière: si le fichier associé
    n'est pas trouvé, charger base, pretty, sysinfos et compat à la place
    Si un module n'est pas trouvé, quitter le script avec die()
    }}}
    !! {{{ulibadd}}}
    {{{
    Ajouter $1 au chemin de recherche de urequire
    }}}
    !! {{{ulibsync}}}
    {{{
    Synchroniser les modules de ulib dans le répertoire $1
    }}}
    !! {{{ulibver}}}
    {{{
    Vérifier que la version actuelle de ulib est au moins à la version $1
    (inclue) et éventuellement au plus à la version $2 (exclue)
    }}}
    !! {{{ulibver_require}}}

    !! {{{eerror}}}
    !! {{{die}}}
    !! {{{uprovided}}}
    !! {{{uprovide}}}
    !! {{{urequire}}}
    !! {{{ulibadd}}}
    !! {{{ulibsync}}}
    !! {{{ulibver}}}
    !! {{{ulibver_require}}}

    !! {{{vcs_getvcs_help}}}
    !! {{{vcs_getvcs}}}
    !! {{{vcs_getroot_help}}}
    !! {{{vcs_getroot}}}
    !! {{{vcs_getrepos_help}}}
    !! {{{vcs_getrepos}}}
    !! {{{vcs_geturl_help}}}
    !! {{{vcs_geturl}}}
    !! {{{vcs_vcs_help}}}
    !! {{{vcs_vcs}}}
    !! {{{vcs_add_help}}}
    !! {{{vcs_add}}}
    {{{
    le répertoire de référence est le répertoire du premier fichier ajouté
    }}}
    !! {{{vcs_remove_help}}}
    !! {{{vcs_remove}}}
    {{{
    le répertoire de référence est le répertoire du premier fichier supprimé
    }}}
    !! {{{vcs_copy_help}}}
    !! {{{vcs_copy}}}
    {{{
    le répertoire de référence est le répertoire de destination
    }}}
    !! {{{vcs_move_help}}}
    !! {{{vcs_move}}}
    {{{
    le répertoire de référence est le répertoire de destination
    }}}
    !! {{{vcs_mkdir_help}}}
    !! {{{vcs_mkdir}}}
    {{{
    le répertoire de référence est le répertoire du premier répertoire créé
    }}}
    !! {{{vcs_commit_help}}}
    !! {{{vcs_commit}}}
    !! {{{vcs_status_help}}}
    !! {{{vcs_status}}}
    !! {{{vcs_update_help}}}
    !! {{{vcs_update}}}
    !! {{{vcs_push_help}}}
    !! {{{vcs_push}}}
    !! {{{vcs_diff_help}}}
    !! {{{vcs_diff}}}
    !! {{{vcs_tag_help}}}
    !! {{{vcs_tag}}}
    !! {{{git_getrepos}}}
    !! {{{git_geturl}}}
    !! {{{git_have_annex}}}
    !! {{{git_add}}}
    !! {{{git_remove}}}
    !! {{{git_copy}}}
    !! {{{git_move}}}
    !! {{{git_mkdir}}}
    !! {{{git_commit}}}
    !! {{{git_status}}}
    !! {{{git_update}}}
    !! {{{git_push}}}
    !! {{{git_diff}}}
    !! {{{git_tag}}}
    !! {{{git_check_gitvcs}}}
    !! {{{git_ensure_gitvcs}}}
    !! {{{git_list_branches}}}
    !! {{{git_list_rbranches}}}
    !! {{{git_list_pbranches}}}
    {{{
    lister les branches locales et celles qui existent dans l'origine
    $1(=origin) et qui pourraient devenir une branche locale avec la commande
    git checkout -b
    }}}
    !! {{{git_have_branch}}}
    !! {{{git_have_rbranch}}}
    !! {{{git_get_branch}}}
    !! {{{git_get_branch_remote}}}
    !! {{{git_get_branch_merge}}}
    !! {{{git_get_branch_rbranch}}}
    !! {{{git_is_branch}}}
    !! {{{git_have_remote}}}
    !! {{{git_track_branch}}}
    !! {{{git_ensure_branch}}}
    {{{
    retourner 0 si la branche a été créée, 1 si elle existait déjà, 2 en cas d'erreur
    }}}
    !! {{{git_check_cleancheckout}}}
    {{{
    vérifier qu'il n'y a pas de modification locales dans le dépôt
    correspondant au répertoire courant.
    }}}
    !! {{{git_ensure_cleancheckout}}}
    !! {{{git_is_ancestor}}}
    {{{
    vérifier que la branche $1 est un ancêtre direct de la branche $2, qui
    vaut par défaut refs/remotes/${3:-origin}/$1
    note: cette fonction retourne vrai si $1 et $2 identifient le même commit
    }}}
    !! {{{git_should_ff}}}
    {{{
    vérifier si la branche $1 devrait être fast-forwardée à partir de la
    branche d'origine $2, qui vaut par défaut refs/remotes/${3:-origin}/$1
    note: cette fonction est similaire à git_is_ancestor(), mais retourne
    false si $1 et $2 identifient le même commit
    }}}
    !! {{{git_should_push}}}
    {{{
    vérifier si la branche $1 devrait être poussée vers la branche de même nom
    dans l'origine $2(=origin), parce que l'origin peut-être fast-forwardée à
    partir de cette branche.
    }}}
    !! {{{git_fast_forward}}}
    {{{
    vérifier que la branche courante est bien $1, puis tester s'il faut la
    fast-forwarder à partir de la branche d'origine $2, puis le faire si c'est
    nécessaire. la branche d'origine $2 vaut par défaut refs/remotes/origin/$1
    }}}
    !! {{{git_is_merged}}}
    {{{
    vérifier que les branches $1 et $2 ont un ancêtre commun, et que la
    branche $1 a été complètement fusionnée dans la branche destination $2
    }}}
    !! {{{git_annex_initial}}}
    {{{
    sur le dépôt $1 fraichement cloné, vérifier s'il faut faire git annex
    init. Si oui, l'initialiser avec le nom d'hôte, et récupérer tous les
    fichiers annexés
    retourner 1 si une erreur s'est produite
    }}}
    !! {{{svn_getrepos}}}
    !! {{{svn_geturl}}}
    !! {{{svn_add}}}
    !! {{{svn_remove}}}
    !! {{{svn_copy}}}
    !! {{{svn_move}}}
    !! {{{svn_mkdir}}}
    !! {{{svn_commit}}}
    !! {{{svn_status}}}
    !! {{{svn_update}}}
    !! {{{svn_push}}}
    !! {{{svn_diff}}}
    !! {{{svn_tag}}}
    !! {{{cvs_getrepos}}}
    !! {{{cvs_geturl}}}
    !! {{{cvs_add}}}
    !! {{{cvs_remove}}}
    !! {{{cvs_copy}}}
    !! {{{cvs_move}}}
    !! {{{cvs_mkdir}}}
    !! {{{cvs_commit}}}
    !! {{{cvs_status}}}
    !! {{{cvs_update}}}
    !! {{{cvs_push}}}
    !! {{{cvs_diff}}}
    !! {{{cvs_tag}}}

    !! {{{virsh_filter}}}
    {{{
    filtrer une sortie liste de virsh. En pratique, ne prendre que les lignes
    non vides à partir de la ligne "----*"
    }}}
    !! {{{virsh_list}}}
    !! {{{virsh_pool_list}}}
    !! {{{guess_vm_type}}}
    {{{
    Afficher hn, kvm, vmware, virtualbox ou openvz suivant que l'on est
    *probablement* respectivement sur une machine physique, une machine
    virtuelle kvm, vmware, virtualbox, openvz
    XXX pour le moment, seuls openvz, kvm et hn sont supportés
    }}}

    !! {{{compute_webobjects_prefixes}}}
    !! {{{recompute_webobjects_prefixes}}}
    !! {{{get_NEXT_ROOT_prefix}}}
    !! {{{get_WOROOT_prefix}}}
    !! {{{get_LOCALROOT_prefix}}}
    !! {{{get_SYSTEMFRAMEWORKS_prefix}}}
    !! {{{get_WOEXTENSIONS_prefix}}}
    !! {{{get_WOFRAMEWORKS_prefix}}}
    !! {{{get_WOAPPLICATIONS_prefix}}}
    !! {{{get_WOCONFIGURATION_prefix}}}
    !! {{{get_WOAUTOSTART_prefix}}}
    !! {{{get_WOLOGS_prefix}}}
    !! {{{get_WOVERSION_prefix}}}
    !! {{{is_wobundle}}}
    {{{
    Tester si $1 a un nom de bundle valide, c'est à dire avec l'extension .woa
    ou .framework
    }}}
    !! {{{is_woappdir}}}
    {{{
    Tester si $1 est un répertoire d'application webobjects. Le test est
    effectué sur le contenu du bundle, pas sur le nom (utiliser is_wobundle()
    pour cela)
    }}}
    !! {{{is_wofwkdir}}}
    {{{
    Tester si $1 est un répertoire de framework webobjects. Le test est
    effectué sur le contenu du bundle, pas sur le nom (utiliser is_wobundle()
    pour cela)
    }}}
    !! {{{get_app_winclspth}}}
    {{{
    calculer la valeur de Contents/Windows/CLSSPATH.txt pour l'application $1
    }}}
    !! {{{get_infofile}}}
    {{{
    Obtenir le chemin vers le fichier Info.plist dans le répertoire de
    resource du bundle $1
    }}}
    !! {{{read_infofile}}}
    {{{
    Lire la version et le numéro de release dans le fichier $1 (chemin vers
    Info.plist) et les placer dans les variables $2(=version) et $3(=release)
    Retourner 1 si un erreur s'est produite, par exemple si le fichier $1
    n'existe pas ou n'est pas accessible en lecture
    }}}
    !! {{{write_infofile}}}
    {{{
    Ecrire $2 (la version) et $3 (le numéro de release) dans le fichier $1
    (chemin vers Info.plist)
    Retourner 1 si un erreur s'est produite, par exemple si le fichier $1
    n'existe pas
    }}}
    !! {{{get_jawotoolsfile}}}
    {{{
    Obtenir le chemin vers le fichier jawotools.properties dans le bundle $1
    }}}
    !! {{{read_jawotoolsfile}}}
    {{{
    lire le fichier de propriété $1 et placer les valeurs dans les variables
    $2(=version), $3(=releaseDate), $4(=description)
    }}}
    !! {{{save_jawotoolsfile}}}
    {{{
    écrire le fichier de propriété $1 avec les valeurs version ($2),
    releaseDate ($3) et description ($4)
    }}}
    !! {{{get_versionfile}}}
    {{{
    Obtenir le chemin vers le fichier VERSION.txt dans le répertoire de
    resource du bundle $1
    }}}
    !! {{{get_configfile}}}
    {{{
    obtenir le chemin vers le fichier de configuration du répertoire de
    resource du bundle
    $1=bundle ou resdir (appdir/Contents/Resources ou fwkdir/Resources)
    }}}
    !! {{{searchreplace_classpath}}}
    {{{
    Dans les fichiers classpath de l'application $1, remplacer $2 par $3. Si
    $3 est vide, la ligne est supprimée
    }}}
    !! {{{dump_jars}}}
    {{{
    Afficher les jars des frameworks utilisés par l'application $1
    }}}
    !! {{{dump_frameworks}}}
    {{{
    Afficher les frameworks utilisés par l'application $1
    }}}
    !! {{{remove_framework}}}
    {{{
    supprimer le framework $2 (nom de base) des fichiers de classpath du
    bundle d'application $1
    }}}
    !! {{{add_framework}}}
    {{{
    s'il n'y existe pas déjà, ajouter le framework $2 (nom de base ou chemin
    absolu) aux fichiers de classpath du bundle d'application $1
    }}}
    !! {{{fix_jars_case}}}
    {{{
    Vérifier que la casse des jars de tous les frameworks utilisés par
    l'application $1 est conforme au système de fichier
    }}}
    !! {{{verifix_bundle}}}
    {{{
    vérifier et corriger le bundle $1. Pour une application, on vérifie que le
    script est exécutable. Pour un framework, on vérifie que le framework est
    conforme au modèle des framework générés par WebObjects.
    }}}
    !! {{{compute_fapps}}}
    {{{
    Placer dans le tableau $1(=fappnames) la liste des noms de bundle
    d'applications qui dépendent du framework $2
    Cette opération est faite à partir des informations sur le système de
    fichier. Elle ne peut donc concerner qu'une installation locale.
    }}}
    !! {{{woraurl}}}
    {{{
    Faire une requête avec la méthode $1 sur l'url $2 avec le payload $3 (par
    exemple pour la méthode POST). la réponse est disponible dans le fichier
    $WORAURL_DATA, $4(=http_code) contient le code de réponse.
    Retourner 0 en cas de succès, ou une valeur différente de zéro si un
    erreur se produit (typiquement, 3 pour une erreur du serveur, 1 pour une
    réponse applicative, comme par exemple si l'application n'existe pas)
    Les codes de réponse 2xx et 417 sont des succès
    Les autres codes (à priori 4xx ou 5xx) sont des erreurs
    note: le code 417 est utilisé par le moniteur pour répondre "Non", par
    opposition à 200 utilisé pour répondre "OUI"
    }}}
    !! {{{wogeturl}}}
    !! {{{splitins}}}
    {{{
    Analyser le nom $1, qui peut être de forme '', 'Name.woa',
    'Name.framework', 'App' ou 'Instance-N' (où N est un nombre), et
    initialiser les variables $2(=type) et $3(=name)
    Si $1=="", type=all et name=""
    Si $1==Name.woa, type=woa et name=Name.woa
    Si $1==Name.framework, type=fwk et name=Name.framework
    Si $1==App, type=app et name=App
    si $1==App-N, type=ins et name=App-N
    }}}
    !! {{{create_wodirs_maybe}}}
    !! {{{check_autostart}}}
    {{{
    vérifier la présence du fichier $WOAUTOSTART. Si ce n'est pas le cas, le
    créer avec le contenu du tableau $1
    }}}
    !! {{{get_autostart_order}}}
    {{{
    Initialiser le tableau $1 avec la liste donnée dans le fichier
    $WOAUTOSTART
    }}}
    !! {{{apply_autostart_order}}}
    {{{
    Réordonner les valeurs $3..* selon la liste donnée dans le tableau $2,
    puis placer le résultat dans le tableau $1. $2 doit être construit avec
    get_autostart_order(). Si $2 n'est pas spécifié, la liste est construite
    localement.
    Si le tableau contient des lignes de délai @N, replacer les délais après
    les applications appropriées
    }}}
    !! {{{wotaskd_stop}}}
    !! {{{wotaskd_start}}}
    !! {{{javamonitor_stop}}}
    !! {{{womonitor_stop}}}
    !! {{{javamonitor_start}}}
    !! {{{womonitor_start}}}
    !! {{{woservices_stop}}}
    !! {{{woservices_start}}}

    !! {{{date2version}}}
    !! {{{woconf}}}
    !! {{{wotag}}}
    !! {{{woinst}}}

    !! {{{wom__statistics}}}
    {{{
    Afficher les statistiques pour le serveur $1, avec éventuellement le mot
    de passe $2
    }}}
    !! {{{wom__info}}}
    {{{
    Contacter le moniteur sur l'hôte $2, avec éventuellement le mot de passe
    $3, et afficher des informations sur l'application $1 (par défaut, all)
    }}}
    !! {{{wom__info_filter}}}
    {{{
    filtrer le résultat de wom__info en ne gardant que les tags
    name, state, activeSessions, autoRecover, deaths, host, port
    }}}
    !! {{{wom_info}}}
    {{{
    Contacter le moniteur sur l'hôte $3, avec éventuellement le mot de passe
    $4, et initialiser le tableau $1 avec une liste de valeurs quotés de la
    forme:
    "'name' 'state' 'activeSessions' 'autoRecover' 'deaths' 'host' 'port'"
    concernant l'application $2 (par défaut, toutes les applications). Notez
    qu'il y a une ligne par instance d'application
    Ces valeurs peuvent être utilisées comme arguments d'une fonction. par
    exemple:
    wom_info appinfos "" host pw
    for args in "${appinfos[@]}"; do
    eval "userfunc $args"
    done
    }}}
    !! {{{wom_getValidAndRunning}}}
    {{{
    Placer la liste des applications valides dans le tableau $1(=valid_apps)
    et la liste des applications qui tournent dans le tableau
    $2=(running_apps), en contactant le moniteur sur l'hôte $3, avec
    éventuellement le mot de passe $4.
    }}}
    !! {{{show_appinfo}}}
    {{{
    Afficher des informations sur une application. Les arguments doivent être
    le résultat de la fonction wom_info()
    }}}
    !! {{{wom_running}}}
    {{{
    Contacter le moniteur sur l'hôte $2, avec éventuellement le mot de passe
    $3, et tester si l'application $1 (par défaut, all) tourne actuellement
    }}}
    !! {{{wom_start}}}
    {{{
    Contacter le moniteur sur l'hôte $2, avec éventuellement le mot de passe
    $3, et démarrer l'application $1 (par défaut, all)
    }}}
    !! {{{wom_stopped}}}
    {{{
    Contacter le moniteur sur l'hôte $2, avec éventuellement le mot de passe
    $3, et tester si l'application $1 (par défaut, all) est actuellement arrêtée
    }}}
    !! {{{wom_stop}}}
    {{{
    Contacter le moniteur sur l'hôte $2, avec éventuellement le mot de passe
    $3, et arrêter l'application $1 (par défaut, all)
    }}}
    !! {{{wom_forceQuit}}}
    {{{
    Contacter le moniteur sur l'hôte $2, avec éventuellement le mot de passe
    $3, et forcer l'arrêt de l'application $1 (par défaut, all)
    }}}
    !! {{{wom_turnScheduledOn}}}
    {{{
    Contacter le moniteur sur l'hôte $2, avec éventuellement le mot de passe
    $3, et activer le flag scheduled sur l'application $1 (par défaut, all)
    }}}
    !! {{{wom_turnScheduledOff}}}
    {{{
    Contacter le moniteur sur l'hôte $2, avec éventuellement le mot de passe
    $3, et désactiver le flag scheduled sur l'application $1 (par défaut, all)
    }}}
    !! {{{wom_turnRefuseNewSessionOn}}}
    {{{
    Contacter le moniteur sur l'hôte $2, avec éventuellement le mot de passe
    $3, et activer le flag refuseNewSession sur l'application $1 (par défaut,
    all)
    }}}
    !! {{{wom_turnRefuseNewSessionOff}}}
    {{{
    Contacter le moniteur sur l'hôte $2, avec éventuellement le mot de passe
    $3, et désactiver le flag refuseNewSession sur l'application $1 (par
    défaut, all)
    }}}
    !! {{{wom_turnAutoRecoverOn}}}
    {{{
    Contacter le moniteur sur l'hôte $2, avec éventuellement le mot de passe
    $3, et activer le flag autoRecover sur l'application $1 (par défaut, all)
    }}}
    !! {{{wom_turnAutoRecoverOff}}}
    {{{
    Contacter le moniteur sur l'hôte $2, avec éventuellement le mot de passe
    $3, et désactiver le flag autoRecover sur l'application $1 (par défaut,
    all)
    }}}
    !! {{{wom_bounce}}}
    {{{
    Contacter le moniteur sur l'hôte $2, avec éventuellement le mot de passe
    $3, et redémarrer l'application $1 (par défaut, all) en mode bounce
    }}}
    !! {{{wom_clearDeaths}}}
    {{{
    Contacter le moniteur sur l'hôte $2, avec éventuellement le mot de passe
    $3, et effacer le compte des morts suspectes pour l'application $1 (par
    défaut, all)
    }}}
    !! {{{wom__getApplications}}}
    {{{
    Obtenir des information sur la définition de l'application $1 (ou de
    toutes les applications si $1=="") en contactant le moniteur sur l'hôte $2
    avec éventuellement le mot de passe $3. Le résultat est un flux xml,
    chaque application étant défini dans un tag <MApplications>. Si un erreur
    se produit, l'erreur est dans un tag <Strings>
    }}}
    !! {{{wom__getApplications_filter}}}
    {{{
    filtrer le résultat de wom__getApplications en ne gardant que les tags
    name, unixPath, macPath, winPath
    }}}
    !! {{{wom_getApplications}}}
    {{{
    Obtenir la liste des applications définies en contactant le moniteur sur
    l'hôte $3 avec éventuellement le mot de passe $4, et initialiser le
    tableau $1 avec une liste de valeurs quotées de la forme:
    "'name' 'unixPath' 'macPath' 'winPath'"
    concernant l'application $2 (par défaut, toutes les applications)
    Ces valeurs peuvent être utilisées comme arguments d'une fonction. par
    exemple:
    wom_getApplications appinfos "" host pw
    for args in "${appinfos[@]}"; do
    eval "userfunc $args"
    done
    }}}
    !! {{{wom_addApplication}}}
    {{{
    Ajouter une application nommée $1 en contactant le moniteur sur l'hôte $2,
    avec éventuellement le mot de passe $3.
    Soit le nom Name, par défaut l'exécutable se trouve dans
    WOAPPLICATIONS/Name.woa/Name et les logs dans /var/log/WebObjects, et le
    flag autoRecover est activé
    XXX supporter la possibilité de modifier les valeurs par défaut
    }}}
    !! {{{wom_addInstance}}}
    {{{
    Ajouter une instance sur localhost pour l'application nommée $1 en
    contactant le moniteur sur l'hôte $2, avec éventuellement le mot de passe
    $3.
    XXX supporter la possibilité de modifier les valeurs par défaut
    }}}
    !! {{{check_compute_apps_localhost}}}
    {{{
    si les arguments de compute_apps contiennent des bundles de framework, il
    faut avoir accès au système de fichier local. vérifier si l'un des
    arguments $2..* est un framework. si c'est le cas, vérifier que l'hôte $1
    est localhost.
    retourner 0 si c'est ok, 1 s'il y a des frameworks et que host n'est pas
    localhost
    }}}
    !! {{{compute_apps}}}
    {{{
    Remplir le tableau $1(=apps) avec la liste des applications correspondant
    aux arguments $3...*
    Un bundle de framework (Name.framework) est remplacé par la liste des
    bundles d'applications qui dépendent de ce framework. Cette information
    est obtenue en consultant le système de fichier local.
    Un bundle d'application est remplacé par la liste des applications qui
    sont définies pour ce bundle. Cette information est obtenue en consultant
    le tableau généré par wom_getApplications(), dont le nom est $2
    Les arguments de la forme @N sont ignorés, ils correspondent à des délais
    à respecter lors du démarrage de l'application
    }}}
    !! {{{get_error_msg}}}
    !! {{{start_apps}}}
    {{{
    Démarrer les applications $3..$* en contactant le moniteur sur l'hôte $1
    avec le mot de passe éventuel $2
    Les variables globales enable_autorecover et force_enable_autorecover
    permettent respectivement d'activer l'autoRecover après le démarrage de
    l'application et de forcer l'activation de l'autoRecover même si
    l'instance tournait déjà.
    Un argument de la forme @N provoque une attente de N secondes. Ceci permet
    de placer un temps d'attente entre le démarrage de certaines applications.
    }}}
    !! {{{stop_apps}}}
    {{{
    Arrêter les applications $3..$* en contactant le moniteur sur l'hôte $1
    avec le mot de passe éventuel $2
    Les variables globales disable_autorecover et force_disable_autorecover
    permettent respectivement de désactiver l'autoRecover après l'arrêt de
    l'application et de forcer la désactivation de l'autoRecover même si
    l'instance ne tournait pas.
    L'option {-a ARRAY} permet de remplir ARRAY avec la liste des applications
    qui ont été effectivement arrêtées. Cette option si elle est spécifiée
    doit être en premier
    Pour compatibilité avec start_apps, les arguments de la forme @N sont
    ignorés. Il n'y a pas de temps d'attente entre les applications lors de
    l'arrêt.
    }}}
    !! {{{bounce_apps}}}
    {{{
    Redémarrer les applications $3..$* en mode bounce en contactant le
    moniteur sur l'hôte $1 avec le mot de passe éventuel $2
    Pour compatibilité avec start_apps, les arguments de la forme @N sont
    ignorés. Il n'y a pas de temps d'attente entre les applications lors du
    redémarrage.
    }}}

    !! {{{wosign_setup_maybe}}}
    !! {{{wosign_jar}}}
    !! {{{wosignable}}}
    !! {{{wosign}}}
    {{{
    Signer un bundle, les jars d'un répertoire, ou un jar
    L'option -f force la resignature des jars d'un répertoire ou d'un
    bundle. Elle force aussi la signature d'un jar, même s'il semble qu'il
    soit la version signée d'un autre jar
    on présuppose que wosignable a retourné true
    }}}

    !! {{{wot_config}}}
    {{{
    Afficher la configuration de wotaskd
    }}}

    {{{
    ulibshell: Lancer un shell après avoir chargé des modules de ulib

    USAGE
        ulibshell [options] [args...]

    OPTIONS
        -r module
            Spécifier un module à charger avec urequire. Plusieurs modules peuvent
            être spécifiés en les séparant par ':'

    Un shell est lancé dans lequel les modules spécifiés sont chargés. Par défaut,
    seul le module DEFAULTS est chargé. Les arguments sont passés inchangés au
    shell.
    }}}

    {{{
    ulibsync: Copier les librairies ulib et/ou pyulib

    USAGE
        ulibsync [options] destdir

    OPTIONS
        -u  Copier ulib
        -p  Copier pyulib
    }}}

    {{{
    ulink: déplacer, supprimer, copier un fichier ou un lien

    Quand on déplace ou qu'on copie un lien, la destination du lien est mise à jour

    USAGE
        ulink mv files... dest
        ulink cp files... dest
        ulink rm files...

    OPTIONS
        -d UPDATEDIR
            Chercher dans UPDATEDIR tous les liens qui pointent vers le fichier
            concerné, et mettre à jour ces liens après avoir déplacé le fichier, ou
            supprimer ces liens si le fichier est supprimé.
    }}}

    {{{
    umatch: Afficher le résultat d'une recherche par regexp et compter
    éventuellement leurs occurences

    USAGE
        umatch [options] [regexp]

    Chaque ligne *entière* de stdin est mise en correspondance avec l'expression
    regulière qui doit avoir la syntaxe de awk. S'il y a correspondance, afficher
    soit toute l'expression matchée, soit chaque groupe s'il y a des expressions
    parenthésées, chacun des groupes étant séparé par le caractère sep.

    Si l'expression régulière n'est pas spécifiée, elle vaut par défaut '.*' ce qui
    fait que toutes les lignes correspondent. Ceci peut être utile avec les options
    -s et -c.

    Certaines expressions régulières sont prédéfinies. regexp peut avoir l'une des
    valeurs prédéfinies suivantes:

        ip --> [0-9]+\.[0-9]+\.[0-9]+\.[0-9]+

    OPTIONS
        -F sep
            Spécifier le caractère séparateur en sortie s'il faut afficher des
            champs multiples. Par défaut, utiliser le caractère ':'
            Si un séparateur vide est spécifié, le séparateur standard de awk est
            utilisé.
        -s  Trier le résultat
        -C FIELDNUM
        -c, --count
            Compter les occurences successives de la valeur du champ FIELDNUM, et
            afficher une ligne de la forme 'count<sep>last_line' pour chaque groupe,
            last_line étant la dernière occurence du groupe. L'option -c correspond
            à '-C 0', c'est à dire compter les occurences successives de toute les
            lignes.
            Le séparateur utilisé pour calculer le numéro de champ est sep, spécifié
            avec l'option -F.
        -a, --all-lines
            Avec les options -c/-C, afficher toutes les lignes des occurences
            successives au lieu de seulement la ligne de la dernière occurence. Ceci
            est utile surtout avec l'option -C, pour voir les différences avec les
            différentes lignes.
        -m, --multiple
            Avec les options -c/-C, n'afficher que les lignes dont le compte est
            supérieur à 1. Avec l'option -a, les groupes contigus sont séparés par
            une ligne '--'
    }}}

    {{{
    umirror: faire un miroir d'un site web

    USAGE
        umirror [options] url [wget_options]

    OPTIONS
        -l
            Convertir les liens pour consultation locale
    }}}

    {{{
    USAGE:
        upassword -p [-f aeskeyfile] [clear [salts...]]
        upassword -p [-f aeskeyfile] -j JKEY codetu [salts...]
        upassword -p -f aeskeyfile -k crypted [salts...]
        upassword -f aeskeyfile -G [password [salt]]
        upassword -f aeskeyfile -s
        upassword -f aeskeyfile -e clear
        upassword -f aeskeyfile -d crypted
        upassword --batch

    OPTIONS
        -p, --hash-password
            Crypter un mot de passe (option par défaut). Si le mot de passe en clair
            et/ou le salt ne sont pas spécifiés, ils sont choisis au hasard.
        -j, --clear-is-codetu JKEY
            Indiquer que l'argument clear est un numéro d'étudiant, à partir duquel
            il faut générer le mot de passe. Cette option n'est valide qu'avec -p
        -k, --clear-is-crypted
            Indiquer que l'argument clear doit d'abord être décrypté avec la clé AES
            spécifiée avant utilisation. Cette option n'est valide qu'avec -p
        -G, --aes-genkey
            Générer une clé AES pour utilisation avec les options -s, -e, -d
        -s, --aes-showkey
            Afficher encodée en base64 la clé AES contenue dans le fichier spécifié
        -e, --aes-encrypt
            Crypter un mot de passe avec la clé AES spécifiée
        -d, --aes-decrypt
            Décrypter un mot de passe avec la clé AES spécifiée
        -f, --aes-keyfile
            Spécifier le fichier contenant la clé AES. Cette option est obligatoire
            avec les options -G, -s, -e et -d
        --shell
            Afficher les valeurs pour évaluation par le shell

    MODE BATCH
    Utiliser l'option --batch active le mode batch. Dans ce mode, chaque ligne est
    un ensemble d'arguments, comme si on avait lancé le script à plusieurs reprises.
    L'analyseur est limité: le découpage des arguments est fait sur les espaces.
    Les lignes commençant par # sont ignorées.
    Si une ligne commence par --batch-after, alors cette ligne est affichée après
    chaque résultat. Ceci permet de générer un script qui peut être évalué.

    Voici un exemple:
        upassword --batch <<EOF
        --batch-after process_password1 args
        --shell
        --shell fixed-password1
        --batch-after process_password2 args
        --shell fixed-password2
        EOF
    Le résultat serait quelque chose comme:
        clear='<random-password>'
        ... # toutes les valeurs lm, ntlm, crypt, sha, xsha, ssha, md5, smd5
        process_password1 args
        clear='fixed-password1'
        ... # toutes les valeurs lm, ntlm, crypt, sha, xsha, ssha, md5, smd5
        process_password1 args
        clear='fixed-password2'
        ... # toutes les valeurs lm, ntlm, crypt, sha, xsha, ssha, md5, smd5
        process_password2 args
    }}}

    {{{
    update-nutools: mettre à jour nutools
    }}}

    {{{
    uprefix: Afficher les préfixes valides pour uinst

    USAGE
        uprefix -l|--dump|prefix...

    OPTIONS
        -l
            Afficher la liste des préfixes valides
        --dump
            Afficher la liste des préfixes valides et leurs valeurs
        prefix
            Afficher la valeur du préfixe spécifié
    }}}

    {{{
    uproject: Outil pour gérer des projets

    USAGE
        uproject cmd [args]

    COMMANDS
        getvcs [dir]
            Afficher le type de VCS pour dir.
        getroot [dir]
            Si dir est un répertoire versionné, retourner le répertoire racine du
            projet versionné.
        getrepos [dir]
            Si dir est un répertoire versionné, retourner l'url du repository du
            projet versionné.
        geturl [dir]
            Si dir est un répertoire versionné, retourner son url dans le
            repository.
        fold [dir]
        unfold [dir]
            Utiliser uinc pour défaire (resp. refaire) toutes les inclusions des
            fichiers de dir. Cela nécessite qu'un fichier .udir soit configuré à la
            racine du projet avec uinc=true
        vcs [args]
            Appeler le gestionnaire de gestion approprié avec les arguments donnés.
        add files...
            Ajouter les fichiers files dans le gestionnaire de version.
        remove files...
            Supprimer les fichiers versionnés files.
        copy from to
            Copier le fichier versionné from vers le fichier to.
        move from to
            Renommer le fichier versionné from vers le fichier to.
        mkdir dir
            Créer un nouveau répertoire versionné.
        commit message [files...]
            Enregistrer les modifications (par défaut sur tous les fichiers
            modifiés) avec le commentaire message.
        status
            Afficher l'état des fichiers versionnés et non versionnés.
        update [-x]
            Mettre à jour la copie locale avec la copie sur le serveur.
            -x  Ne pas mettre à jour les références externes (si appliquable)
            -n, --no-autoff
                Ne pas faire de fast-forward automatique pour toutes les branches
                traquées. Par défaut, s'il n'y a pas de modifications locales,
                essayer de fast-fowarder toutes les branches locales traquées.
        diff [options]
            Afficher les différences.
            -l  Afficher les différences non commitées (par défaut)
            -c  Afficher les différences en passe d'être commitées (si appliquable)
            -r REV
                Afficher les différences depuis la révision REV.
            -R  Afficher les modifications effectuées depuis la dernière release.

        clone git@host:path/to/repo [destdir]
            Cloner un dépôt distant. Initialiser git annex si le dépôt contient des
            fichiers annexés. Récupérer aussi ces fichiers avec 'git annex get'

        crone git@host:path/to/repo [destdir]
            Créer un dépôt distant sur gitolite, puis le cloner

        develop
        release
        hotfix
            Démarrer le travail sur une branche respectivement de développement, de
            release, ou de correction de bugs. Lancer chaque commande avec --help
            pour les détails. Nécessite git.

        archive
            Créer une archive du projet courant. Nécessite git.

        annex [args]
            Lancer git annex avec les arguments spécifiés.
        xadd
        xunlock
        xdrop
        xwhereis
        xwebapp
            Chacune de ces commandes est un raccourci vers la commande
            correspondante de git annex, sans le préfixe 'x'
        xsync
            Sur un dépot où git-annex est activé, lancer 'git annex sync' si on est
            en mode indirect ou 'git annex sync --content' si on est en mode direct.
            Sur un dépôt où git-annex n'est pas activé, faire l'équivalent des
            commandes 'git add -A && git commit && git pull && git push'
        xcopy
        xmove
        xget
            Comme ci-dessus, mais si la commande s'exécute sans erreur, lancer
            aussi 'git annex sync'
        xinitial
            Sur un dépôt fraichement cloné, initialiser le dépôt avec 'annex init'
            s'il contient des fichiers annexés. Récupérer aussi ces fichiers avec
            'annex get'
        xconfig-export [dir]
            Installer des hooks pour qu'un dépôt puisse être utilisé pour servir des
            fichiers, par exemple avec un serveur web. Plus précisément, un hook
            post-receive est créé avec la commande 'git annex merge', et un hook
            post-update est créé avec la commande 'git update-server-info'

        printml [-t TYPE]
            Afficher le modeline pour un fichier du type spécifié
        addml [-t TYPE] file
            Ajouter un modele pour le fichier spécifié, s'il n'en a pas déjà un.
            Si nécessaire, forcer le type du fichier au lieu de l'autodétecter
        new [options] file [template options]
            Créer un nouveau fichier à partir d'un modèle.
            Avant le nom du fichier, les options suivantes sont valides:
            -t TEMPLATE
                Spécifier le modèle de fichier à utiliser. Par défaut, le modèle
                à utiliser est déduit de l'extension ou du nom du fichier.
            -e  Editer le fichier après l'avoir créé.
            Après le nom du fichier, toutes les options sont spécifiques au modèle
            utilisé pour créer le nouveau fichier. Utiliser l'option --help pour
            avoir une description des options disponibles.
    }}}

    {{{
    uscrontab: lancer une suite de commande en respectant une planification de type cron

    USAGE
        uscrontab [options] [/path/to/uscrontab] [var=value...]
        uscrontab -e [/path/to/uscrontab]
        uscrontab -l

    La première forme du script doit normalement être lancé toutes les minutes par
    une tâche cron. Utiliser l'option --install pour ajouter automatique la ligne
    dans la crontab de l'utilisateur.

    Avec la première forme du script, le fichier spécifié est traité. Si aucun
    fichier n'est spécifié, fusionner s'il existe le fichier
        /var/local/uscrontab/users/jclain
    avec chacun des fichiers du répertoire
        /var/local/uscrontab/users.d/jclain
    dans un fichier temporaire, puis exécuter le fichier résultat avec le nom
    virtuel
        /var/local/uscrontab/jclain
    note: le nom virtuel est utilisé pour le verrouillage avec --lock

    A chaque lancement de ce script, le fichier /path/to/uscrontab spécifié est
    examiné pour déterminer quels commandes doivent être exécutées. Ce fichier est
    composé de lignes dans un format particulier, qui sont analysées et traitées
    dans l'ordre.

    Quelles que soient les lignes qui sont sélectionnées pour l'exécution, elles
    sont garanties de s'exécuter dans l'ordre du fichier, l'une après l'autre.

    Les définitions var=value mentionnées sur la ligne de commande sont des
    définitions de variables à effectuer avant de lancer les commandes.

    Les lignes commençant par # sont des commentaires et sont ignorées

    == Définitions de variables et exécution de commandes ==

        Les lignes de la forme suivante sont des définitions de variable:

            [export] var="valeur de la variable"

        Ces lignes sont des définitions de variable bash qui sont exécutées telles
        quelles. Il n'est donc pas autorisé de mettre des espaces autour de =. Par
        exemple, les lignes suivantes sont des erreurs de syntaxe:

            var = bad
            var=pas de quotes autour de la valeur

        alors que celles-ci sont correctes:

            var=ok
            var="valeur avec des espaces"
            var='on peut utiliser des quotes aussi'

        Il est possible de manipuler les variables de type PATH avec une syntaxe
        particulière de l'opérateur d'assignation. Les opérateurs += et %= utilisent
        uaddpath(), #= utilise uinspath() et -= utilise udelpath(). Par exemple, les
        lignes suivantes ajoutent respectivement /usr/local/nutools puis enlèvent
        /opt/rogue au PATH:

            PATH+=/usr/local/nutools
            PATH-=/opt/rogue

        Bien sûr, il ne faut pas oublier de quoter les espaces:

            PATH+="/path/to/dir with spaces"

        La syntaxe ?= permet de définir la valeur d'une variable si elle n'est pas
        déjà définie:

            var?=default

        Les lignes de la forme suivante permettent d'exécuter une commande qui est
        exécutée systématiquement et ignore la planification:

            $one-line-command

        Une variante permet de spécifier des commandes sur plusieurs lignes.
        ATTENTION! ${ et $} doivent être tous seuls sur la ligne.

            ${
            several
            commands
            ...
            $}

        Ces commandes sont exécutées systématiquement et ignorent la planification.
        On peut s'en servir notamment pour lire un fichier de configuration qui
        définit des variables ou des fonctions:

            $source path/to/file

        Le code d'erreur de ces commandes est ignoré, contrairement à ce qui se
        passe pour les commandes qui font l'objet d'une planification.

    == Planification de commandes ==

        Les autres lignes doivent être au format d'une ligne de crontab:

            minutes hours days months dows command-line

        command-line peut être n'importe quelle ligne de commande bash, pourvu
        qu'elle soit sur une seule ligne.

        Certaines extensions par rapport à la syntaxe de crontab sont autorisées. Il
        est en particulier possible de spécifier plusieurs planifications pour une
        seule commande. Par exemple, les lignes suivantes permettent d'exécuter
        'command' toutes les heures ET à 1h05:

            0 * * * *
            5 1 * * * command

        Il est aussi possible d'utiliser la même planification pour plusieurs
        commandes sans devoir répéter la définition de la planification. Les lignes
        suivantes planifient command1 et command2 toutes les heures:

            0 * * * * command1
                      command2

        Pour être prise en compte, la ligne command2 doit commencer par au moins un
        espace ou une tabulation. Pour la lisibilité, la syntaxe suivante est
        supportée aussi:

            0 * * * *
              command1
              command2

        Les deux formats peuvent être utilisés ensemble. Par exemple les lignes
        suivantes exécutent command1 et command2 toutes les heures ET à 1h05:

            0 * * * *
            5 1 * * * command1
                      command2

        Par défaut, le script s'arrête à la première commande planifiée qui retourne
        avec un code d'erreur. Il est possible d'ignorer le code d'erreur d'une
        commande avec nostop, e.g:

            0 * * * * nostop command

        Cf aussi l'option --continuous pour modifier le comportement par défaut

    == Fonctions disponibles ==

        La fonction check_pidfile() est disponible, et permet de vérifier qu'une
        opération n'est pas déjà en cours. Si cette fonction est utilisée, il ne
        faut pas modifier la valeur de -k. Par exemple:

            0 1 * * *
              check_pidfile /path/to/pid [args]
              long-running-script

        check_pidfile() doit être utilisée toute seule sur la ligne et s'utilise
        avec les argument suivants:

            check_pidfile PIDFILE [DESC] [BARRIER]

        - PIDFILE est le fichier de PID qui est vérifié
        - DESC est la description du traitement qui est effectué. La valeur par
          défaut est "Une synchronisation". Si le fichier de PID est présent, le
          message suivant est affiché:
            DESC est en cours.
            Si vous pensez que c'est une erreur, veuillez vérifier le process de pid PID
            puis supprimez le cas échéant le fichier PIDFILE
        - BARRIER est un fichier qui est créé avec le contenu 'PID' s'il n'existe
          pas encore, et si la vérification du fichier de PID est faite avec succès.
          La présence de ce fichier peut-être vérifiée par un processus externe pour
          empêcher par exemple de mettre à jour les scripts pendant qu'il sont en
          train de tourner.
          Son contenu peut être examiné pour connaître le PID du processus qui l'a
          créé initialement. Le fichier est automatiquement supprimé à la fin de ce
          script.
          Attention: ce fichier n'est pas un verrou, il peut être supprimé à tout
          moment. Notamment, si deux scripts sont configurés pour créer le même
          fichier barrière, le premier script supprimera le fichier barrière avant
          la fin de l'exécution du second script.

        La fonction remove_pidfile() permet de supprimer un fichier de pid pour
        spécifier qu'une opération est terminée. Considérons l'exemple suivant:

            0 1 * * *
              check_pidfile /path/to/pid
              script1
              script2
              remove_pidfile /path/to/pid
              script3

        Dans cet exemple, il ne faut pas qu'une autre occurence de script1 tourne
        pendant que script2 tourne. Par contre, plusieurs occurences de script3
        peuvent tourner en parallèle.

        La fonction elogto() permet de spécifier un fichier vers lequel toutes les
        sorties sont redirigées.

    OPTIONS
        -A, --install
            Installer une planification toutes les minutes du script dans la crontab
            de l'utilisateur. Si l'argument /path/to/uscrontab n'est pas spécifié,
            c'est une planification générique qui exécute les fichiers par défaut
            qui est installée.
        -R, --uninstall
            Désinstaller la planification toutes les minutes du script de la crontab
            de l'utilisateur. Si l'argument /path/to/uscrontab est spécifié, cette
            instance est désinstallée. Sinon, ne désinstaller que la planification
            générique.
        -d, --disable-only
            Avec l'option -R, désactiver la planification au lieu de la supprimer.
        -e, --edit
            Lancer un editeur pour modifier l'uscrontab spécifiée. Si aucun fichier
            n'est spécifié, éditer /var/local/uscrontab/users/jclain
        -a, --add
            Installer un script uscrontab dans le répertoire approprié. L'argument
            doit être de la forme [name:]/path/to/uscrontab
            Si name n'est pas spécifié, le nom de base du fichier spécifié est
            utilisé. Si name est vide ou vaut $USER (soit jclain en l'occurence),
            copier le fichier spécifié vers le chemin /var/local/uscrontab/users/jclain
            Sinon, copier le fichier spécifié vers /var/local/uscrontab/users.d/jclain/name
        -r, --remove
            Supprimer le script uscrontab spécifié. L'argument doit être le nom du
            script à supprimer.  Si l'argument n'est pas spécifié ou vaut $USER
            (soit jclain en l'occurence), supprimer le fichier /var/local/uscrontab/users/jclain
            s'il existe
        -l, --list
            Si l'argument /path/to/crontab est spécifié, afficher le contenu de ce
            fichier. Sinon, lister les contenus des fichiers crontab qui sont
            exécutés avec la planification actuelle. Si une planification générique
            est installée, ou si aucune planification n'est en cours, afficher le
            contenu du fichier
                /var/local/uscrontab/users/jclain
            et chacun des fichiers du répertoire
                /var/local/uscrontab/users.d/jclain
        -n, --fake
            Afficher au lieu de les exécuter les commandes qui doivent être lancées
        -P, --pause-for NBMINS
            Désactiver les planifications pendant NBMINS minutes. Utiliser -1 pour
            désactiver les planifications sans limite de durée. Pendant la période
            de pause, toutes les invocations de uscrontab n'ont aucun effet, sauf si
            on utilise l'option --force
        -Y, --unpause
            Réactiver les planifications après une mise en pause
        -p, --pause
            Désactiver les planifications pendant 1 journée. Equivalent à -P 1440
        -f, --force
            Forcer l'exécution de la planification, même si elle a été mise en pause
            avec l'option --pause

    OPTIONS AVANCEES
        --lock LOCKFILE
            Inscrire dans le fichier spécifié des informations permettant d'éviter
            les invocations simultanées de ce script. Si selon ce fichier, le script
            tourne depuis plus de 8 heures, un message d'erreur
            est consigné et un message d'avertissement est affiché au plus une fois.
            Utiliser --lock '' pour désactiver cette fonctionnalité
            Par défaut, si ce script est lancé en root, le fichier utilisé pour le
            verrouillage est de la forme /var/run/uscrontab/abspath/to/crontab
            Si le script est lancé avec un compte utilisateur, aucun verrouillage
            n'est effectué.
        --lockdelay LOCKDELAY[=8]
            Changer le nombre d'heures pendant lesquelles on autorise le script a
            verrouiller l'exécution avant d'afficher un avertissement.
        -c, --continuous
            Par défaut, ce script s'arrête à la première commande planifiée qui
            retourne avec un code d'erreur. Notez que les codes d'erreur des
            commandes sans planification sont toujours ignorés. Avec cette option,
            ce script ne s'arrête jamais, bien qu'il retourne toujours un code
            d'erreur si une erreur s'est produite.  Il est possible d'ignorer le
            code d'erreur pour une commande en particulier avec le préfixe nostop
        -k, --stopec EXITCODE[=101]
            Spécifier un code d'erreur spécial qui arrête ce script sans erreur, ou
            '' pour désactiver cette fonctionnalité. Ceci permet en début de script
            de faire des tests par exemple sur l'environnement avant de lancer les
            scripts planifiés. Si l'environnement ne convient pas, il suffit au
            script de contrôle de retourner le code d'erreur spécifique pour arrêter
            le traitement.
        --show-ctnow
            Afficher l'heure de référence au format crontab 'min hou day mon dow'
            Cette valeur peut être utilisée avec l'option --force-ctnow dans des
            tests pour reproduire une condition spécifique.
        --force-ctnow 'min hou day mon dow'
            Pour le développement ou des tests, forcer la valeur de l'heure de
            référence. Il faut respecter le format, sinon les résultats ne sont pas
            garantis. Le mieux est de reprendre le résultat de l'option --show-ctnow
            en le modifiant un peu si nécessaire.
    }}}

    {{{
    ussh: se connecter par ssh à un ou plusieurs hôtes

    USAGE
        ussh [options] hosts
        ussh [options] @hostsfile
        ussh -r hosts
        ussh --parse hosts

    OPTIONS
        hosts
        @hostsfile
            Spécifier un ou plusieurs hôtes distants sur lequels faire la connexion.
            Pour spécifier plusieurs hôtes, il faut les séparer par un espace ou le
            caractère ':', e.g. 'host1 host2' ou 'host1:host2'. Si la spécification
            contient les caractères { et }, l'expansion est effectuée, e.g
                'root@{host1,host2}.univ.run'
            La forme @hostsfile permet de lire la liste des hôtes depuis le fichier
            hostsfile, à raison d'un hôte par ligne.

    Toutes les options de ssh sont reconnues. Les options longues suivantes sont
    reconnues comme alias de certaines options courtes de ssh:
        --quiet
            alias de -q, activer le mode non verbeux
        --tty
            alias de -t, forcer l'allocation d'un TTY
        --login USER
            alias de -l, spécifier le user avec lequel se connecter
        --port PORT
            alias de -p, spécifier le port sur lequel se connecter

    Les options suivantes sont exclusives à ce script:
        -d, --domain DOMAIN
            Spécifier un domaine par défaut pour les hôtes qui sont spécifiés sans
            domaine.
        -z, --ssh SSH
            Spécifier l'exécutable à utiliser pour lancer ssh.
        -r, --remove
            Lancer 'ssh-keygen -R' pour chacun des hôtes spécifiés avant de s'y
            connecter. Par exemple:
                ussh -r host.tld
            est équivalent à:
                ssh-keygen -R host.tld
                ssh-keygen -R host
                ssh-keygen -R 10.10.1.5
                ssh host.tld
            si l'adresse ip de host.tld est 10.10.1.5
            Quand cette option est spécifié, l'option -j est reconnue et permet de
            NE PAS se reconnecter à l'hôte juste après avoir nettoyé les clés. Avec
            l'option -j, TOUS les arguments sont des noms d'hôte puisqu'aucune
            connexion n'est effectuée.
        --exec
        --no-exec
            Avec --exec, si un seul hôte est spécifié, lancer le processus ssh avec
            exec, pour éviter d'encombrer la mémoire. C'est l'option par défaut.
            Avec --no-exec, ne jamais utiliser exec pour lancer ssh.
        --parse
            Afficher la définition des variables ssh, options, hosts et args qui
            permettent d'effectuer la connexion à partir d'un autre script. Exemple:
                eval "$(ussh --parse args...)"
                for host in "${hosts[@]}"; do
                    ${exec:+exec} "$ssh" "${options[@]}" "$host" "${args[@]}"
                done
        --cc
            Assumer que nutools est installé sur l'hôte distant, et y lancer uwatch
            avec l'option --cc, pour permettre de garder la connexion active dans le
            cadre d'une redirection de port.

    Si la variable UTOOLS_USSH_RSYNC_SUPPORT contient une valeur non vide, l'analyse
    des arguments s'arrête à la première valeur qui n'est pas une option, afin de
    permettre l'utilisation de ce script avec l'option -e de rsync.
    }}}

    {{{
    usysinfos: Afficher les informations sur le système

    USAGE
        usysinfos [query]

    Si la requête est spécifiée, tester si le système courant correspond à la
    requête. Voir la doc de check_sysinfos() pour le format de la requête.

    Sinon, afficher les informations sur le système courant.
    }}}

    {{{
    utempl: Créer un nouveau fichier à partir d'un modèle

    USAGE
        utempl [options] file [template options]

    OPTIONS
    Avant le nom du nouveau fichier, les options suivantes peuvent être utilisées:
        -t TEMPLATE
            Spécifier le modèle de fichier à utiliser. Par défaut, le modèle
            à utiliser est déduit de l'extension ou du nom du fichier.
        -e, --edit
            Editer le fichier après l'avoir créé
        -g, --no-edit
            Ne pas éditer le fichier après l'avoir créé

    Après le nom du fichier, toutes les options sont spécifiques au modèle
    utilisé pour créer le nouveau fichier. Utiliser l'option --help pour
    avoir une description des options disponibles.
    }}}

    {{{
    utrigger: lancer une commande en différé

    USAGE
        utrigger [options] -- command [args]

    La commande est lancée après un certain temps, sauf si ce script est rappelé
    (auquel cas le compte est réinitialisé), ou si l'opération est annulée.
    Attention! La commande est lancée en tâche de fond, et son entrée standard est
    connectée à un fichier qui peut être provisionné avec l'option -a

    note: ce script ne fonctionne que sous Linux puisqu'il utilise la commande flock

    OPTIONS
        -n, --name NAME
            Spécifier un nom identifiant la tâche. Par défaut, le nom est généré à
            partir des détails de la tâche à lancer. Ce nom est utilisé pour
            identifier les invocations successives.
        -f, --cmdfile CMDFILE
            Spécifier un fichier contenant les commandes à lancer. Le fichier est
            sourcé dans un sous-shell. Utiliser - pour lire les commandes depuis
            l'entrée standard.
        --rundelay RUNDELAY[=5]
            Nombre de secondes au bout desquelles la commande est lancée. Si ce
            script est relancé avant la fin de ce décompte, le compte est remis à
            zéro.
            Utiliser --rundelay '' pour désactiver cette fonctionnalité, auquel cas
            la commande est lancée immédiatement.
        -s, --sudo
            Forcer l'exécution de la commande avec l'utilisateur root si ce n'est
            pas déjà le cas
        -a, --datafile DATAFILE
            Accumuler des données à fournir à la commande. Les informations du
            fichier DATAFILE (utiliser - pour l'entrée standard) sont ajoutées à un
            fichier temporaires, et sont fournies en une seule fois à la commande
            sur son entrée standard.
        -A, --data DATA
            Variante de --datafile où les données sont fournies sur la ligne de
            commande au lieu d'un fichier externe. Si les deux options -a et -A sont
            spécifiées, les données sont accumulées dans l'ordre --datafile puis
            --data
        -k, --cancel
            Annuler le lancement planifié d'une commande. Si la commande est déjà en
            train de tourner, cette option n'a aucun effet.
    }}}

    {{{
    uwatch: afficher l'heure

    USAGE
        uwatch [options]

    OPTIONS
        -t, --time
            Afficher l'heure (par défaut)
        -c, --count
            Afficher le temps écoulé depuis le lancement de ce script
        -u, --units
            Avec l'option --count, afficher l'unité: sec., min. ou heures
        -o, --offset NBSEC
            Avec l'option --count, spécifier un nombre de secondes à partir duquel
            compter
        -s, --step NBSECS[=1]
            Spécifier la période de rafraichissement de l'affichage
        -a, --prefix PREFIX
            Spécifier une chaine à afficher avant l'heure
        -z, --suffix SUFFIX
            Spécifier une chaine à afficher après l'heure
        --cc
            Equivalent à -c -s 5 -a 'Connecté sur $MYHOST depuis ' -z '...'
            Permet de garantir une activité sur une connexion SSH utilisée
            uniquement pour faire une redirection de port
    }}}

    {{{
    vzusage: afficher des informations sur une machine virtuelle OpenVZ

    USAGE
        vzusage [options] [params...]d

    OPTIONS
        -b  Afficher les informations de /proc/user_beancounters
        -f  N'afficher que les valeurs pour lesquelles failcnt > 0.
            Implique -b
        -z coef
            Afficher les instructions à utiliser pour augmenter de coef% les
            valeurs pour lesquelles failcnt > 0. Implique -f
        -c config|veid
            Afficher les informations du fichier de configuration plutôt que les
            beancounters
    }}}

    {{{
    woArchive: créer une archive de la distribution WebObjects en cours
    USAGE
        woArchive [-n name] [-f files]

    OPTIONS
        -n NAME
            Nom de base de l'archive. Par défaut il s'agit de WebObjects-<version>

        -f FILES
            Nom de la liste des fichiers de l'archives. Par défaut il s'agit de
            $NAME.files
    }}}

    {{{
    woSwitch: Changer la version de WebObjects pour le système en cours
    USAGE
        woSwitch [-f from.files] to-archive.tar.gz

    OPTIONS
        -f from.files
            Spécifier la liste des fichiers pour la version de WebObjects
            installée. Par défaut, il s'agit de WebObjects-<version>.files
            La liste doit correspondre à la version en cours.

        -F  Forcer l'installation, même si la version en cours ne correspond pas à ce
            qui est inscrit dans from.files

        to-archive.tar.gz
            Nom de l'archive qui contient la version à installer.

    Ce script ne fonctionne que sur MacOS X
    Le contenu des répertoires suivants est sauvegardé avant le changement:
        /Library/WebObject/Applications
        /Library/WebObject/Configuration
        /Library/WebObject/Extensions
    Ensuite, les répertoires Applications et Configuration sont restaurés. Il faudra
    restaurer Extensions manuellement.
    }}}

    {{{
    woctl: Contrôler des applications WebObjects

    USAGE
        woctl [options] action args
        wostart args...
        wostop args...
        wobounce args...
        worestart args...

    OPTIONS
        -h HOST
            Spécifier l'hôte qui fait tourner le moniteur sous la forme host[:port]
        -p PASSWORD
            Spécifier le mot de passe pour le moniteur

    ACTIONS
        Dans les arguments des actions ci-dessous, une application peut être
        spécifiée sous la forme App ou App.woa. Spécifier une application revient à
        spécifier toutes les instances configurées pour cette application.
        Si on spécifie un framework sous la forme Fwk.framework, cela revient à
        spécifier toutes les applications qui dépendent de ce framework.
        Sinon, une instance individuelle est de la forme App-N, où N est un entier
        positif.

        status
            afficher l'état des instances qui tournent actuellement
        version
            afficher la version de WebObjects installée
        wotaskd
        javamonitor
        woservices
            piloter wotaskd/javamonitor
        _create
            créer une instance par défaut dans javamonitor
        configure
            configurer un bundle
        tag
            ajouter une information de version à un bundle
        run
            lancer une application localement en mode debug
        download
            télécharger une application ou un framework
        start apps...
            démarrer une ou plusieurs applications
        stop apps...
            arrêter une ou plusieurs applications
        restart apps...
            relancer une ou plusieurs applications
        bounce apps...
            relancer une ou plusieurs applications en mode bounce
    }}}

    {{{
    woinst: Déployer un bundle (application ou framework) de WebObjects

    USAGE
        woinst [options] <file|archive|dir>...

    OPTIONS
        PREFIX=value
            Spécifier une valeur pour un préfixe, plutôt que de laisser uprefix
            l'autodétecter. Utiliser uprefix -l pour une liste de préfixes valides.
        -b  Redémarrer les instances en mode bounce.
            Par défaut, les instances sont arrêtées avant le déploiement, et
            redémarrées après
        -W  Ne déployer que les resources web. Implique -n
        -n  Ne pas tagger les bundles déployés avec un numéro de version. Par
            défaut, l'utilisateur est invité à compléter des informations telles
            que n° de version et date de release si ces informations ne sont pas
            disponible.
        -x CMD
            Exécuter la commande CMD après avoir effectué le déploiement
    }}}

    {{{
    wosign: signer les jars d'un bundle

    USAGE
        wosign <app.woa|fwk.framework|file.jar>

    OPTIONS
        -f  Forcer la (re)signature des jars
        -d  Enlever la signature des jars originaux
        -s  Signer les jar du bundle [PAR DEFAUT]
        --init
            Initialiser les fichiers de configuration pour la signature des bundles.
        --sudo
            Si le répertoire de destination des fichiers de configuration n'est
            accessible en écriture, relancer le script en root.
    }}}