Term::Shell::MultiCmd - Nested Commands Tree in Shell Interface
# Examples are available with the distribution, under directory 'examples/' # This one is named examples/synopsis.pl use Term::Shell::MultiCmd; my @command_tree = ( 'multi word command' => { help => "Help title.", opts => 'force repeat=i', exec => sub { my ($o, %p) = @_ ; print "$p{ARG0} was called with force=$p{force} and repeat=$p{repeat}\n" }, }, 'multi word another command' => { help => 'Another help title. Help my have multi lines, the top one would be used when one linear needed.', comp => sub { # this function would be called when use hits tab completion at arguments my ($o, $word, $line, $start, $op, $opts) = @_ ; # .. do something, then return qw/a list of completion words/ ; }, exec => sub { my ($o, %p) = @_ ; print "$p{ARG0} was called\n"}, }, 'multi word third command' => { help => 'same idea', comp => [qw/a list of words/], # this is also possible exec => sub { my ($o, %p) = @_ ; print "$p{ARG0} was called. Isn't that fun?\n"}, }, 'multi word' => 'You can add general help title to a path', ) ; Term::Shell::MultiCmd -> new() -> populate( @command_tree ) -> loop ; print "All done, see you later\n" ;
To get the most from a command line, it might be a good idea to get the latest versions of Term::ReadLine and Term::ReadKey. There are numberless ways of doing it, one of them is running 'cpan update Bundle::CPAN' (with a proper write permission).
my $cli = new Term::Shell::MultiCmd ; - or - my $cli = Term::Shell::MultiCmd->new( [optional parameters ...] ) ;
The parameters to the constructor are passed in hash form, preceding dash is optional.
Optional Parameters for the new command:
-prompt
my $cli = new Term::Shell::MultiCmd ( -prompt => 'myprompt') ; - or - my $cli = mew Term::Shell::MultiCmd ( -prompt => \&myprompt) ;
Overwrite the default prompt 'shell'. Rules are:
If prompt is a CODE reference, call it in each loop cycle and display the results. if it ends with a non-word character, display it as is. Else, display it with the root-path (if exists) and '> ' characters.
-help_cmd
Overwrite the default 'help' command, empty string would disable this command.
-quit_cmd
Overwrite the default 'quit' command, empty string would disable this command.
-root_cmd
my $cli = new Term::Shell::MultiCmd ( -root_cmd => 'root' ) ;
This would enable the root command and set it to root.
Unlike 'quit' and 'help', the 'root' command is a little unexpected. Therefore it is disabled by default. I strongly recommend enabling this command when implementing a big, deep command tree. This allows the user rooting in a node, then referring to this node thereafter. After enabling, use 'help root' (or whatever names you've chosen) for usage manual.
-history_file
my $cli = new Term::Shell::MultiCmd ( -history_file => "$ENV{HOME}/.my_progarms_data" ) ;
This is the history file name. If present, try to load history from this file just before the loop command, and try saving history in this file after the loop command. Default is an empty string (i.e. no history preserved between sessions). Please note that things might get tricky if that if multiple sessions are running at the same time.
-history_size
Overwrite the default 100 history entries to save in hisotry_file (if exists).
-history_more
If the history_file exists, try to load this data from the file during initialization, and save it at loop end. For Example:
my %user_defaults ; my $cli = new Term::Shell::MultiCmd ( -history_file => "$ENV{HOME}/.my_saved_data", -history_size => 200, -history_more => \%user_defaults, ) ; # .... $cli -> loop ;
This would load shell's history and %user_defaults from the file .my_saved_data before the loop, and store 200 history entries and %user_defaults in the file after the loop.
Note that the value of history_more must be a reference for HASH, ARRAY, or SCALAR. And no warnings would be provided if any of the operations fail. It wouldn't be a good idea to use it for sensitive data.
-pager
As pager's value, this module would expect a string or a sub that returns a FileHandle. If the value is a string, it would be converted to:
sub { use FileHandle ; new FileHandle "| $value_of_pager" }
When appropriate, the returned file handle would be selected before user's command execution, the old one would be restored afterward. The next example should work on most posix system:
my $cli = new Term::Shell::MultiCmd ( -pager => 'less -rX', ...
The default pager's value is empty string, which means no pager manipulations.
-pager_re
Taking after perldb, the default value is '^\|' (i.e. a regular expression that matches '|' prefix, as in the user's command "| help"). If the value is set to an empty string, every command would trigger the pager.
The next example would print any output to a given filehandle:
my $ret_value ; my $cli = new Term::Shell::MultiCmd ( -pager => sub { open my $fh, '>', \$ret_value or die "can't open FileHandle to string (no PerlIO?)\n" ; $fh }, -pager_re => '', ) ; # ... $cli -> cmd ('help -t') ; print "ret_value is:\n $ret_value" ;
-record_cmd
If it's a function ref, call it with an echo of the user's command
my $cli = new Term::Shell::MultiCmd ( -record_cmd => sub { my $user_cmd = shift; system "echo '$user_cmd' >> /tmp/history" } ) ;
-empty_cmd
Function ref only, call it when user hits 'Return' with no command or args (not even spaces)
my $cli = new Term::Shell::MultiCmd ( -empty_cmd => sub { # Assuming some commands are recorded in $last_repeatable_cmd if ( $last_repeatable_cmd ) { # repeat it } } ) ;
-query_cmd
If exeuting a node, and node contains the query cmd, it would be executed instead of the help command (on the node) Default: 'query' For exmaple, with this feature, if "my cmd query" exists, it would also be exeuted at "my cmd'
my $cli = new Term::Shell::MultiCmd ( -query_cmd => 'query', ) ; =item * -enable_sh_pipe
If true, allow redirect output to a shell command by the suffix ' | <chell cmd>'. Example: Shell> my multy path cmd | grep -w 42 Default is value is 1, To disable, set it to false (0 or '' or undef)
my $cli = new Term::Shell::MultiCmd ( -enable_sh_pipe => '', ) ;
Note: If both pager and this pipe are used, the pipe will be ingored and the command will get whole line as argument.
$cli -> add_exec ( -path => 'full command path', -exec => \&my_command, -help => 'some help', -opts => 'options', -comp => \&my_completion_function, ) ;
This function adds an command item to the command tree. It is a little complicated, but useful (or so I hope).
-path
Mandatory. Expecting a string. This string would be parsed as multi-words command.
Note: by default, this module expects whitespaces delimiter. If you'll read the module's code, you can find an easy way to change it - in unlikely case you'll find it useful.
-exec
Mandatory. Expecting a function ref. This code would be called when the user types a unique path for this command (with optional options and arguments). Parameters sent to this code are:
my ($cli, %p) = @_ ; # where: # $cli - self object. # $p{ARG0} - the command's full path (user might have used partial but unique path. This is the explicit path) # $p{ARGV} - all user arguments, in order (ARRAY ref) # %p - contains other options (see 'opts' below)
-help
Expecting a multi line string. The top line would be presented when a one line title is needed (for example, when 'help -tree' is called), the whole string would be presented as the full help for this item.
-comp
Expecting CODE, or ARRAY ref, or HASH ref. If Array, when the user hits tab completion for this command, try to complete his input with words from this list. If Hash, using the hash keys as array, following the rule above. If Code, call this function with the next parameters:
my ($cli, $word, $line, $start) = @_ ; # where: # $cli is the Term::Shell::MultiCmd object. # $word is the curent word # $line is the whole line # $start is the current location
This code should return a list of strings. Term::ReadLine would complete user's line to the longest common part, and display the list (unless unique). In other words - it would do what you expect.
For more information, see Term::ReadLine.
-opts
Expecting a string, or ARRAY ref. If a string, split it to words by whitespaces. Those words are parsed as standard Getopt::Long options. For example:
-opts => 'force name=s flag=i@'
This would populating the previously described %p hash, correspond to user command:
shell> user command -name="Some String" -flag 2 -flag 3 -flag 4 -force
For more information, see Getopt::Long. Also see examples/multi_option.pl in distribution.
As ARRAY ref, caller can also add a complete 'instruction' after each non-flag option (i.e. an option that expects parameters). Like the 'comp' above, this 'instruction' must be an ARRAY or CODE ref, and follow the same roles. When omitted, a default function would be called and ask the user for input. For example:
-opts => [ 'verbose' => 'file=s' => \&my_filename_completion, 'level=i' => [qw/1 2 3 4/], 'type=s' => \%my_hash_of_types, ],
Although help string can set in add_exec, this command is useful when he wishes to add title (or hint) to a part of the command path. For example:
# assume $cli with commands 'feature set', 'feature get', etc. $cli -> add_help ( -path => 'feature' , -help => 'This feature is about something') ;
A convenient way to define a chain of add_exec and add_help commands. This function expects hash, where the key is the command path and the value might be HASH ref (calling add_exec), or a string (calling add_help). For example:
$cli -> populate ( 'feature' => 'This feature is a secret', 'feature set' => { help => 'help for feature set', exec => \&my_feature_set, opts => 'level=i', comp => \&my_feature_set_completion_function, }, 'feature get' => { help => 'help for feature get', exec => \&my_feature_get }, ) ; # Note: # - Since the key is the path, '-path' is omitted from parameters. # - This function returns the self object, for easy chaining (as the synopsis demonstrates).
$cli -> loop ;
Prompt, parse, and invoke in an endless loop
('endless loop' should never be taken literally. Users quit, systems crash, universes collapse - and the loop reaches its last cycle)
$cli -> cmd ( "help -tree" ) ;
Execute the given string parameter, similarly to user input. This one might be useful to execute commands in a script, or testing.
$cli -> command ( "help -tree") ; Is the same as cmd, but echos the command before execution
my ($base_line, @word_list) = $cli -> complete ($a_line) ;
given a line, this function would return a base line (i.e. truncated to the beginning of the last word), and a list of potential completions. Added to the 'cmd' command, this might be useful when module user implements his own 'loop' command in a non-terminal application
my $prompt = $cli -> prompt() ;
accepts no parameters, return current prompt.
set/get history
my @hist = $cli -> history() ; # get history $cli -> history( @alternative_history ) ; # set history $cli -> history([@alternative_history]) ; # the very same, by ptr $cli -> history([]) ; # clear history
Term::ReadLine, Term::ReadKey, Getopt::Long
Josef Ezra, <jezra at sign cpan.org>
<jezra at sign cpan.org>
Please report any bugs or feature requests to me, or to bug-term-cli at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Term-CLI. I am grateful for your feedback.
bug-term-cli at rt.cpan.org
nImplement pager.
You can find documentation for this module with the perldoc command.
perldoc Term::Shell::MultiCmd
You can also look for information at:
RT: CPAN's request tracker
http://rt.cpan.org/NoAuth/Bugs.html?Dist=Term-CLI
AnnoCPAN: Annotated CPAN documentation
http://annocpan.org/dist/Term-CLI
CPAN Ratings
http://cpanratings.perl.org/d/Term-CLI
Search CPAN
http://search.cpan.org/dist/Term-CLI/
This module was inspired by the excellent modules Term::Shell, CPAN, and CPANPLUS::Shell.
Copyright 2010 Josef Ezra.
This program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License.
See http://dev.perl.org/licenses/ for more information.
To install Term::Shell::MultiCmd, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Term::Shell::MultiCmd
CPAN shell
perl -MCPAN -e shell install Term::Shell::MultiCmd
For more information on module installation, please visit the detailed CPAN module installation guide.