738 lines
11 KiB
HTML
738 lines
11 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
|
<HTML
|
|
><HEAD
|
|
><TITLE
|
|
>An Introduction to Programmable Completion</TITLE
|
|
><META
|
|
NAME="GENERATOR"
|
|
CONTENT="Modular DocBook HTML Stylesheet Version 1.7"><LINK
|
|
REL="HOME"
|
|
TITLE="Advanced Bash-Scripting Guide"
|
|
HREF="index.html"><LINK
|
|
REL="PREVIOUS"
|
|
TITLE="Important System Directories"
|
|
HREF="systemdirs.html"><LINK
|
|
REL="NEXT"
|
|
TITLE="Localization"
|
|
HREF="localization.html"></HEAD
|
|
><BODY
|
|
CLASS="APPENDIX"
|
|
BGCOLOR="#FFFFFF"
|
|
TEXT="#000000"
|
|
LINK="#0000FF"
|
|
VLINK="#840084"
|
|
ALINK="#0000FF"
|
|
><DIV
|
|
CLASS="NAVHEADER"
|
|
><TABLE
|
|
SUMMARY="Header navigation table"
|
|
WIDTH="100%"
|
|
BORDER="0"
|
|
CELLPADDING="0"
|
|
CELLSPACING="0"
|
|
><TR
|
|
><TH
|
|
COLSPAN="3"
|
|
ALIGN="center"
|
|
>Advanced Bash-Scripting Guide: </TH
|
|
></TR
|
|
><TR
|
|
><TD
|
|
WIDTH="10%"
|
|
ALIGN="left"
|
|
VALIGN="bottom"
|
|
><A
|
|
HREF="systemdirs.html"
|
|
ACCESSKEY="P"
|
|
>Prev</A
|
|
></TD
|
|
><TD
|
|
WIDTH="80%"
|
|
ALIGN="center"
|
|
VALIGN="bottom"
|
|
></TD
|
|
><TD
|
|
WIDTH="10%"
|
|
ALIGN="right"
|
|
VALIGN="bottom"
|
|
><A
|
|
HREF="localization.html"
|
|
ACCESSKEY="N"
|
|
>Next</A
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
><HR
|
|
ALIGN="LEFT"
|
|
WIDTH="100%"></DIV
|
|
><DIV
|
|
CLASS="APPENDIX"
|
|
><H1
|
|
><A
|
|
NAME="TABEXPANSION"
|
|
></A
|
|
>Appendix J. An Introduction to Programmable Completion</H1
|
|
><P
|
|
>The <I
|
|
CLASS="FIRSTTERM"
|
|
>programmable completion</I
|
|
> feature in
|
|
Bash permits typing a partial command, then pressing the
|
|
<B
|
|
CLASS="KEYCAP"
|
|
>[Tab]</B
|
|
> key to auto-complete the command sequence.
|
|
|
|
<A
|
|
NAME="AEN24082"
|
|
HREF="#FTN.AEN24082"
|
|
><SPAN
|
|
CLASS="footnote"
|
|
>[1]</SPAN
|
|
></A
|
|
>
|
|
|
|
If multiple completions are possible, then <B
|
|
CLASS="KEYCAP"
|
|
>[Tab]</B
|
|
>
|
|
lists them all. Let's see how it works.</P
|
|
><P
|
|
> <TABLE
|
|
BORDER="1"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="100%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="SCREEN"
|
|
><TT
|
|
CLASS="PROMPT"
|
|
>bash$ </TT
|
|
><TT
|
|
CLASS="USERINPUT"
|
|
><B
|
|
>xtra[Tab]</B
|
|
></TT
|
|
>
|
|
<TT
|
|
CLASS="COMPUTEROUTPUT"
|
|
>xtraceroute xtrapin xtrapproto
|
|
xtraceroute.real xtrapinfo xtrapreset
|
|
xtrapchar xtrapout xtrapstats</TT
|
|
>
|
|
|
|
|
|
<TT
|
|
CLASS="PROMPT"
|
|
>bash$ </TT
|
|
><TT
|
|
CLASS="USERINPUT"
|
|
><B
|
|
>xtrac[Tab]</B
|
|
></TT
|
|
>
|
|
<TT
|
|
CLASS="COMPUTEROUTPUT"
|
|
>xtraceroute xtraceroute.real</TT
|
|
>
|
|
|
|
|
|
<TT
|
|
CLASS="PROMPT"
|
|
>bash$ </TT
|
|
><TT
|
|
CLASS="USERINPUT"
|
|
><B
|
|
>xtraceroute.r[Tab]</B
|
|
></TT
|
|
>
|
|
<TT
|
|
CLASS="COMPUTEROUTPUT"
|
|
>xtraceroute.real</TT
|
|
>
|
|
</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
>
|
|
</P
|
|
><P
|
|
>Tab completion also works for variables and path names.</P
|
|
><P
|
|
> <TABLE
|
|
BORDER="1"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="100%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="SCREEN"
|
|
><TT
|
|
CLASS="PROMPT"
|
|
>bash$ </TT
|
|
><TT
|
|
CLASS="USERINPUT"
|
|
><B
|
|
>echo $BASH[Tab]</B
|
|
></TT
|
|
>
|
|
<TT
|
|
CLASS="COMPUTEROUTPUT"
|
|
>$BASH $BASH_COMPLETION $BASH_SUBSHELL
|
|
$BASH_ARGC $BASH_COMPLETION_DIR $BASH_VERSINFO
|
|
$BASH_ARGV $BASH_LINENO $BASH_VERSION
|
|
$BASH_COMMAND $BASH_SOURCE</TT
|
|
>
|
|
|
|
|
|
<TT
|
|
CLASS="PROMPT"
|
|
>bash$ </TT
|
|
><TT
|
|
CLASS="USERINPUT"
|
|
><B
|
|
>echo /usr/local/[Tab]</B
|
|
></TT
|
|
>
|
|
<TT
|
|
CLASS="COMPUTEROUTPUT"
|
|
>bin/ etc/ include/ libexec/ sbin/ src/
|
|
doc/ games/ lib/ man/ share/</TT
|
|
>
|
|
</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
>
|
|
</P
|
|
><P
|
|
><A
|
|
NAME="COMPLETEREF"
|
|
></A
|
|
></P
|
|
><P
|
|
>The Bash <B
|
|
CLASS="COMMAND"
|
|
>complete</B
|
|
> and
|
|
<B
|
|
CLASS="COMMAND"
|
|
>compgen</B
|
|
> <A
|
|
HREF="internal.html#BUILTINREF"
|
|
>builtins</A
|
|
> make it
|
|
possible for <I
|
|
CLASS="FIRSTTERM"
|
|
>tab completion</I
|
|
> to
|
|
recognize partial <I
|
|
CLASS="FIRSTTERM"
|
|
>parameters</I
|
|
> and
|
|
<I
|
|
CLASS="FIRSTTERM"
|
|
>options</I
|
|
> to commands. In a very simple case,
|
|
we can use <B
|
|
CLASS="COMMAND"
|
|
>complete</B
|
|
> from the command-line to
|
|
specify a short list of acceptable parameters.</P
|
|
><TABLE
|
|
BORDER="1"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="100%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="SCREEN"
|
|
><TT
|
|
CLASS="PROMPT"
|
|
>bash$ </TT
|
|
><TT
|
|
CLASS="USERINPUT"
|
|
><B
|
|
>touch sample_command</B
|
|
></TT
|
|
>
|
|
<TT
|
|
CLASS="PROMPT"
|
|
>bash$ </TT
|
|
><TT
|
|
CLASS="USERINPUT"
|
|
><B
|
|
>touch file1.txt file2.txt file2.doc file30.txt file4.zzz</B
|
|
></TT
|
|
>
|
|
<TT
|
|
CLASS="PROMPT"
|
|
>bash$ </TT
|
|
><TT
|
|
CLASS="USERINPUT"
|
|
><B
|
|
>chmod +x sample_command</B
|
|
></TT
|
|
>
|
|
<TT
|
|
CLASS="PROMPT"
|
|
>bash$ </TT
|
|
><TT
|
|
CLASS="USERINPUT"
|
|
><B
|
|
>complete -f -X '!*.txt' sample_command</B
|
|
></TT
|
|
>
|
|
|
|
|
|
<TT
|
|
CLASS="PROMPT"
|
|
>bash$ </TT
|
|
><TT
|
|
CLASS="USERINPUT"
|
|
><B
|
|
>./sample[Tab][Tab]</B
|
|
></TT
|
|
>
|
|
<TT
|
|
CLASS="COMPUTEROUTPUT"
|
|
>sample_command</TT
|
|
>
|
|
<TT
|
|
CLASS="COMPUTEROUTPUT"
|
|
>file1.txt file2.txt file30.txt</TT
|
|
>
|
|
</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
><P
|
|
>The <TT
|
|
CLASS="OPTION"
|
|
>-f</TT
|
|
> option to
|
|
<I
|
|
CLASS="FIRSTTERM"
|
|
>complete</I
|
|
> specifies filenames,
|
|
and <TT
|
|
CLASS="OPTION"
|
|
>-X</TT
|
|
> the filter pattern.</P
|
|
><P
|
|
><A
|
|
NAME="COMPGENREF"
|
|
></A
|
|
></P
|
|
><P
|
|
>For anything more complex, we could write a script that
|
|
specifies a list of acceptable command-line parameters.
|
|
The <B
|
|
CLASS="COMMAND"
|
|
>compgen</B
|
|
> builtin expands a list of
|
|
<I
|
|
CLASS="FIRSTTERM"
|
|
>arguments</I
|
|
> to <I
|
|
CLASS="FIRSTTERM"
|
|
>generate</I
|
|
>
|
|
completion matches. </P
|
|
><P
|
|
>Let us take a <A
|
|
HREF="contributed-scripts.html#USEGETOPT2"
|
|
>modified version</A
|
|
>
|
|
of the <EM
|
|
>UseGetOpt.sh</EM
|
|
> script as an example
|
|
command. This script accepts a number of command-line parameters,
|
|
preceded by either a single or double dash. And here is the
|
|
corresponding <I
|
|
CLASS="FIRSTTERM"
|
|
>completion script</I
|
|
>, by
|
|
convention given a filename corresponding to its associated
|
|
command.</P
|
|
><DIV
|
|
CLASS="EXAMPLE"
|
|
><A
|
|
NAME="USEGETOPTEX"
|
|
></A
|
|
><P
|
|
><B
|
|
>Example J-1. Completion script for
|
|
<I
|
|
CLASS="FIRSTTERM"
|
|
>UseGetOpt.sh</I
|
|
></B
|
|
></P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="100%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="PROGRAMLISTING"
|
|
># file: UseGetOpt-2
|
|
# UseGetOpt-2.sh parameter-completion
|
|
|
|
_UseGetOpt-2 () # By convention, the function name
|
|
{ #+ starts with an underscore.
|
|
local cur
|
|
# Pointer to current completion word.
|
|
# By convention, it's named "cur" but this isn't strictly necessary.
|
|
|
|
COMPREPLY=() # Array variable storing the possible completions.
|
|
cur=${COMP_WORDS[COMP_CWORD]}
|
|
|
|
case "$cur" in
|
|
-*)
|
|
COMPREPLY=( $( compgen -W '-a -d -f -l -t -h --aoption --debug \
|
|
--file --log --test --help --' -- $cur ) );;
|
|
# Generate the completion matches and load them into $COMPREPLY array.
|
|
# xx) May add more cases here.
|
|
# yy)
|
|
# zz)
|
|
esac
|
|
|
|
return 0
|
|
}
|
|
|
|
complete -F _UseGetOpt-2 -o filenames ./UseGetOpt-2.sh
|
|
# ^^ ^^^^^^^^^^^^ Invokes the function _UseGetOpt-2.</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
><P
|
|
>Now, let's try it.</P
|
|
><TABLE
|
|
BORDER="1"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="100%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="SCREEN"
|
|
><TT
|
|
CLASS="PROMPT"
|
|
>bash$ </TT
|
|
><TT
|
|
CLASS="USERINPUT"
|
|
><B
|
|
>source UseGetOpt-2</B
|
|
></TT
|
|
>
|
|
|
|
<TT
|
|
CLASS="PROMPT"
|
|
>bash$ </TT
|
|
><TT
|
|
CLASS="USERINPUT"
|
|
><B
|
|
>./UseGetOpt-2.sh -[Tab]</B
|
|
></TT
|
|
>
|
|
<TT
|
|
CLASS="COMPUTEROUTPUT"
|
|
>-- --aoption --debug --file --help --log --test
|
|
-a -d -f -h -l -t</TT
|
|
>
|
|
|
|
|
|
<TT
|
|
CLASS="PROMPT"
|
|
>bash$ </TT
|
|
><TT
|
|
CLASS="USERINPUT"
|
|
><B
|
|
>./UseGetOpt-2.sh --[Tab]</B
|
|
></TT
|
|
>
|
|
<TT
|
|
CLASS="COMPUTEROUTPUT"
|
|
>-- --aoption --debug --file --help --log --test</TT
|
|
>
|
|
</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
><P
|
|
> We begin by <A
|
|
HREF="internal.html#SOURCEREF"
|
|
>sourcing</A
|
|
> the <SPAN
|
|
CLASS="QUOTE"
|
|
>"completion
|
|
script."</SPAN
|
|
> This sets the command-line parameters.
|
|
<A
|
|
NAME="AEN24160"
|
|
HREF="#FTN.AEN24160"
|
|
><SPAN
|
|
CLASS="footnote"
|
|
>[2]</SPAN
|
|
></A
|
|
>
|
|
</P
|
|
><P
|
|
>In the first instance, hitting <B
|
|
CLASS="KEYCAP"
|
|
>[Tab]</B
|
|
> after
|
|
a single dash, the output is all the possible parameters preceded by
|
|
<EM
|
|
>one or more</EM
|
|
> dashes. Hitting <B
|
|
CLASS="KEYCAP"
|
|
>[Tab]</B
|
|
>
|
|
after <EM
|
|
>two</EM
|
|
> dashes gives the possible parameters
|
|
preceded by <EM
|
|
>two or more</EM
|
|
> dashes.</P
|
|
><P
|
|
>Now, just what is the point of having to jump through flaming
|
|
hoops to enable command-line tab completion? <EM
|
|
>It saves
|
|
keystrokes.</EM
|
|
>
|
|
<A
|
|
NAME="AEN24173"
|
|
HREF="#FTN.AEN24173"
|
|
><SPAN
|
|
CLASS="footnote"
|
|
>[3]</SPAN
|
|
></A
|
|
>
|
|
</P
|
|
><P
|
|
>--</P
|
|
><P
|
|
><EM
|
|
>Resources:</EM
|
|
></P
|
|
><P
|
|
>Bash <A
|
|
HREF="http://freshmeat.net/projects/bashcompletion"
|
|
TARGET="_top"
|
|
> programmable completion</A
|
|
> project</P
|
|
><P
|
|
>Mitch Frazier's <A
|
|
HREF="http://www.linuxjournal.com"
|
|
TARGET="_top"
|
|
><I
|
|
CLASS="CITETITLE"
|
|
>Linux Journal</I
|
|
></A
|
|
> article, <A
|
|
HREF="http://www.linuxjournal.com/content/more-using-bash-complete-command"
|
|
TARGET="_top"
|
|
><EM
|
|
>More
|
|
on Using the Bash Complete Command</EM
|
|
></A
|
|
></P
|
|
><P
|
|
>Steve's excellent two-part article, <SPAN
|
|
CLASS="QUOTE"
|
|
>"An Introduction to Bash
|
|
Completion"</SPAN
|
|
>:
|
|
|
|
<A
|
|
HREF="http://www.debian-administration.org/article/An_introduction_to_bash_completion_part_1"
|
|
TARGET="_top"
|
|
>Part
|
|
1</A
|
|
> and
|
|
|
|
<A
|
|
HREF="http://www.debian-administration.org/article/An_introduction_to_bash_completion_part_2"
|
|
TARGET="_top"
|
|
>Part 2</A
|
|
></P
|
|
></DIV
|
|
><H3
|
|
CLASS="FOOTNOTES"
|
|
>Notes</H3
|
|
><TABLE
|
|
BORDER="0"
|
|
CLASS="FOOTNOTES"
|
|
WIDTH="100%"
|
|
><TR
|
|
><TD
|
|
ALIGN="LEFT"
|
|
VALIGN="TOP"
|
|
WIDTH="5%"
|
|
><A
|
|
NAME="FTN.AEN24082"
|
|
HREF="tabexpansion.html#AEN24082"
|
|
><SPAN
|
|
CLASS="footnote"
|
|
>[1]</SPAN
|
|
></A
|
|
></TD
|
|
><TD
|
|
ALIGN="LEFT"
|
|
VALIGN="TOP"
|
|
WIDTH="95%"
|
|
><P
|
|
>This works only from the <I
|
|
CLASS="FIRSTTERM"
|
|
>command
|
|
line</I
|
|
>, of course, and not within a
|
|
script.</P
|
|
></TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
ALIGN="LEFT"
|
|
VALIGN="TOP"
|
|
WIDTH="5%"
|
|
><A
|
|
NAME="FTN.AEN24160"
|
|
HREF="tabexpansion.html#AEN24160"
|
|
><SPAN
|
|
CLASS="footnote"
|
|
>[2]</SPAN
|
|
></A
|
|
></TD
|
|
><TD
|
|
ALIGN="LEFT"
|
|
VALIGN="TOP"
|
|
WIDTH="95%"
|
|
><P
|
|
>Normally the default parameter completion files reside
|
|
in either the <TT
|
|
CLASS="FILENAME"
|
|
>/etc/profile.d</TT
|
|
>
|
|
directory or in <TT
|
|
CLASS="FILENAME"
|
|
>/etc/bash_completion</TT
|
|
>. These autoload on
|
|
system startup. So, after writing a useful completion script, you
|
|
might wish to move it (as <I
|
|
CLASS="FIRSTTERM"
|
|
>root</I
|
|
>, of course)
|
|
to one of these directories.</P
|
|
></TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
ALIGN="LEFT"
|
|
VALIGN="TOP"
|
|
WIDTH="5%"
|
|
><A
|
|
NAME="FTN.AEN24173"
|
|
HREF="tabexpansion.html#AEN24173"
|
|
><SPAN
|
|
CLASS="footnote"
|
|
>[3]</SPAN
|
|
></A
|
|
></TD
|
|
><TD
|
|
ALIGN="LEFT"
|
|
VALIGN="TOP"
|
|
WIDTH="95%"
|
|
><P
|
|
>It has been extensively documented that
|
|
programmers are willing to put in long hours of effort in
|
|
order to save ten minutes of <SPAN
|
|
CLASS="QUOTE"
|
|
>"unnecessary"</SPAN
|
|
>
|
|
labor. This is known as
|
|
<I
|
|
CLASS="FIRSTTERM"
|
|
>optimization</I
|
|
>.</P
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
><DIV
|
|
CLASS="NAVFOOTER"
|
|
><HR
|
|
ALIGN="LEFT"
|
|
WIDTH="100%"><TABLE
|
|
SUMMARY="Footer navigation table"
|
|
WIDTH="100%"
|
|
BORDER="0"
|
|
CELLPADDING="0"
|
|
CELLSPACING="0"
|
|
><TR
|
|
><TD
|
|
WIDTH="33%"
|
|
ALIGN="left"
|
|
VALIGN="top"
|
|
><A
|
|
HREF="systemdirs.html"
|
|
ACCESSKEY="P"
|
|
>Prev</A
|
|
></TD
|
|
><TD
|
|
WIDTH="34%"
|
|
ALIGN="center"
|
|
VALIGN="top"
|
|
><A
|
|
HREF="index.html"
|
|
ACCESSKEY="H"
|
|
>Home</A
|
|
></TD
|
|
><TD
|
|
WIDTH="33%"
|
|
ALIGN="right"
|
|
VALIGN="top"
|
|
><A
|
|
HREF="localization.html"
|
|
ACCESSKEY="N"
|
|
>Next</A
|
|
></TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
WIDTH="33%"
|
|
ALIGN="left"
|
|
VALIGN="top"
|
|
>Important System Directories</TD
|
|
><TD
|
|
WIDTH="34%"
|
|
ALIGN="center"
|
|
VALIGN="top"
|
|
> </TD
|
|
><TD
|
|
WIDTH="33%"
|
|
ALIGN="right"
|
|
VALIGN="top"
|
|
>Localization</TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
></BODY
|
|
></HTML
|
|
> |