NAME

psh - Perl SHell


SYNOPSIS

psh [options] [file]


COPYRIGHT

Copyright (C) 1999-2000 Gregor N. Purdy. All rights reserved. This script is free software. It may be copied or modified according to the same terms as Perl itself.


DESCRIPTION

psh is a Perl program which executes a read-eval loop with enough options so that general behavior reasonably similar to more traditional shells like 'sh' or 'bash' can be achieved, while still allowing arbitrary perl expressions to be evaluated.

By default within psh, the Perl -w flag and 'use strict' are not employed so that the user is not bound by their stipulations. They can both be turned on via a command-line flag; or setting $^W = 1 will turn on warnings, and calling 'use strict' will (almost) do the usual thing if called by the user (see LIMITATIONS, below).


OPTIONS

The command-line arguments to psh are:

 psh [-d] [-w] [-r RC_FILE] [-c STRING ] [FILE1 FILE2 ....]

They are processed in the following order, regardless of what order they are specified in:

If any FILE1 ... arguments are specified on the command line, they will be read and executed and then psh will exit. Otherwise, psh will enter an interactive command loop.


DESCRIPTION

Each line of input is read. psh knows a number of possible strategies for evaluating the line, such as ``send it to system() if it starts with the name of an executable visible in $ENV{PATH}``. (See below for a complete list.) Each strategy in turn (from a user-definable list) examines the command line to see if it can apply, and the first matching strategy evaluates the line. There is a psh configuration variable (see below) which controls whether the perl value of the evaluation is saved and printed after each command.

psh automatically collects several lines of input into a unit processed as a single line if there are unfinished Perl constructs on the line. In particular, if there is an unmatched quote, paren, brace, or square bracket, input is read until these characters match. If an input line contains the Perl ``here document'' construct as in <<XXX, (anywhere on the line), then input is read and accumulated until XXX occurs on a line by itself. Then the accumulated input is processed as if it were a single line.


TOKENIZATION

Some evaluation strategies examine the ``words'' of the input. These are produced by a tokenizer which behaves very similarly to traditional shells: words are broken at whitespace, '&' is a metacharacter which means that it always forms its own word, and backslash and double and single quotes act as quoting characters, preventing word breaks at whitespace and the ``meta-ness'' of &.

If the description of the strategy does not mention the ``words'', then the tokenization is irrelevant to that strategy.


STANDARD EVALUATION STRATEGIES

psh includes the following evaluation strategies, sorted by the order we suggest for @Psh::strategies.

The list of evaluation strategies to try is kept in the configuration variable @Psh::strategies, which defaults to qw(comment bang brace built_in executable fallback_builtin eval). If you want to ensure that ``print'' (for example) refers to the Perl function ``print'' and not ``/usr/bin/print'', try adding the ``perlfunc'' strategy before ``executable''.


GLOBBING

Globbing is used to expand filenames against patterns. Perl Shell understands the sh '*' and '?' globbing characters (where * matches any string and ? matches exactly one character).

In addition, Perl Shell knows the very powerful '**' globbing, replacing many finds in your daily work. '**' will be replaced by 'current directories and all sub directories'. For example:

    grep foo lib/**/*.pm

will search for foo in all *.pm files which are somewhere (recursivly) within the lib directory.


PIPELINES

Pipelines are used to construct processing chains.

    cat a.txt b.txt | wc -l


MANIFEST FILTERS

A manifest filter is a chunk of code that causes the creation of a filter process. They are handy for creating simple one-time filters because they don't require creating a program file, setting permissions and so on.

There are three kinds of manifest filters: quick, grep and substitution.

A quick filter consists of a block of code surrounded by curly braces, with a trailing 'q' modifier. The Perl Shell turns this into a line-by-line filter. For the code in the braces, $_ will contain the line as it was read from input (including any end-of-line character). The filter block should

     ls | { print ++$i, ": $_"; }q

A grep filter consists of a block of code surrounded by curly braces, with a trailing 'g' modifier. The Perl Shell turns this into a line-by-line filter. Only those lines for which the code in the braces returns a true value will be printed. For the code in the braces, @_ will contain the results of splitting $_ with the pattern \s+.

     netstat | { $_[1]>2; }g

A substitution filter consists of a perl-style s/// operator instance. The Perl Shell will turn this into a line-by-line filter that performs the substitution on each line, and then prints the line. For example:

    ls | s/a/b/

A substitution filter is logically equivalent to a block filter containing the substitution and a statement to print the resulting line. The example above is equivalent to:

    ls | { s/a/b/; print; }q 


BUILT-IN FUNCTIONS

The following functions are provided as built-in functions of psh. You can add an additional built-in called 'foo' by setting the hash $Psh::built_ins{foo} to a reference to a subroutine. When a line like ``foo bar $baz'' is then evaluated by the 'built_in' strategy, the string 'bar $baz' will be passed to your subroutine as its only argument. This is precisely the difference between making 'foo' a built-in as opposed to simply defining a procedure main::foo and letting the eval strategy call foo: the built-in subroutine will get the precise input string entered, whereas the ordinary procedure will of course get arguments that have already been evaluated by the Perl evaluator. Which you want depends on the nature of the function being defined.

If $Psh::built_ins{foo} does not exist, but &Psh::Builtins::bi_foo is defined, then foo will still be considered a builtin calling that function. This is primarily to ensure that the original builtins are always accessible, for example if they have been aliased and unaliased.

``Fallback builtins'' are provided similarly to this last option: ``foo'' is a fallback builtin if &Psh::Builtins::Fallback::bi_foo is defined.

For a list of the predefined psh builtins, see Psh::Builtins or use the ``help'' command from within psh.


PSH SCALAR VARIABLES

psh makes a number of variables and functions accessible to the user in the Psh:: package for configuration or utility purposes. Their default values are given in parentheses below. If the variable is also marked ``[late]'', then it is undefined at the start of the .pshrc file, but any value given to it during that file will be used instead of the default setting.

$Psh::bin (the basename of the file psh was invoked by)

The name of the current shell.

$Psh::cmd

The command serial number in the currently-executing processing loop.

$Psh::change_title (1)

If set to true, the environment variable PSH_TITLE will be set to the current working directory to display it in the window title if possible.

$Psh::currently_active (0)

The pid of the process psh will currently forward signals to, or 0 if psh will handle the signals internally. Usually 0 unless psh is waiting for a process in the ``foreground''.

$Psh::debugging (1 if -d option specified, 0 if not)

Whether psh's internal debugging output should be produced.

$Psh::echo (0)

Controls whether the processing loop saves and displays the Perl value of executing a line of input. Three cases are distinguished: a false value, in which case no results are displayed; a subroutine reference, in which case the subroutine is called with the results (this may be multiple arguments if the eval returned an array) and should return true to display, false to not; or a true (scalar) value, in which case any non-undef, non-empty value is displayed.

In addition to displaying the value, it is pushed onto the array determined by $Psh::result_array. Note that scalar values are pushed directly onto this array, but array values are pushed by reference.

$Psh::eval_preamble ("package main;")

Every Perl expression that psh evaluates as part of its read-eval loop is prepended with this string, intended primarily to set the expected package context.

$Psh::executable_expand_arguments (0)

If this variable is true, then the following procedure is applied to each argument ARG of the command line before passing the command line on to ``system'': If ARG starts with a single quote, it is untouched. If ARG starts with a double quote, it is passed to ``eval'', and then double quotes are placed around the result. Otherwise, double quotes are placed around ARG, it is passed to eval, and the result is used directly. The intention of these steps is to do variable substitution of perl variables that appear in the command line as the user would expect, and in a way similar to shells such as bash. For example, if @files = (file1, file2, file3), then 'ls @files' will expand to 'ls file1 file2 file3', whereas 'echo ``@files''' will expand to 'echo ``file1 file2 file3'''.

$Psh::handle_segfaults (0)

If set to true, psh will ignore all segfaults and attempt to continue.

$Psh::ignore_die (0)

If set to true, psh will attempt to continue after internal errors.

$Psh::history_file ("$ENV{HOME}/.${bin}_history") [late]

The filename psh will use to save the command history in from one invocation to the next, if $Psh::save_history is true.

$Psh::history_length (50) [late]

The number of lines of command history to keep.

$Psh::host (the output of "hostname -s") [late]

The short host name of the machine psh is currently running on.

$Psh::login_shell (0)

Set to true if psh is the user's login shell. On systems where this does not apply, set to true unless called from another instance of psh.

$Psh::longhost (the output of "hostname") [late]

The fully qualified host name of the machine psh is running on.

$Psh::prompt ('\s\$') [late]

Controls the prompt string in interactive use, see below.

$Psh::prompt_cont ('> ') [late]

Just like $Psh::prompt, but for continuation lines when multi-line input is being read.

$Psh::window_title ('\w')

Controls the window title in interactive use. See prompt evaluation for escape codes.

$Psh::result_array ('Psh::val')

Controls where the results of Perl evaluations saved via $Psh::echo will go. It may be a reference to an array, or the string name of an array.

$Psh::save_history (1) [late]

If this is true, the command history is saved in $Psh::history_file from one invocation of psh to the next.

$Psh::which_regexp ('^[-a-zA-Z0-9_~+]*$')

When Psh::Util::which is asked to locate a filename in the current PATH, it will only look for filenames which match this regexp. Names that do not match this regexp will automatically come back ``not found''.

$Psh::Strategy::Perlfunc::builtins (0)

If this variable is true, the perlfunc evaluation strategy will also match those Perl builtins determined by %Psh::perl_builtins

$Psh::Strategy::Perlfunc::packages (1)

If this variable is true, the perlfunc evaluation strategy will also match functions with full package specification

$Psh::Strategy::Perlfunc::expand_arguments (0)

If this variable is true, then command lines interpreted by the perlfunc strategy which contain no parens, or braces or commas except in bash-like brace-expansion expressions, will not be simply evaluated. Rather, they will be interpreted much like traditional shells do: the line will be spilt into words, which undergo globbing, brace expansion, and variable expansion, and the resulting array of words is passed to the specified function as its arguments.


PSH ARRAY VARIABLES

@Psh::Completion::netprograms ( ping, ftp, ncftp, ssh, etc. )

Contains names of a number of net based programs for enabling TAB completion of hostnames/bookmarks

@Psh::Completion::bookmarks ( from /etc/hosts )

Supposed to contain your most used IP numbers, hostnames or URLs. Those will be eligible for TAB completion if you use one of the programs in @Psh::Completion::netprograms. psh will initialize this list with your /etc/hosts file

@Psh::history

An array of lines to write to the history file when psh exits, only filled when the ReadLine module doesn't handle the history file.

@Psh::mon ( Jan, Feb, etc. )

An array of month names used in printing dates, for example in prompt strings.

@Psh::strategies ( comment, bang, built_in, executable, eval)

The list of strategies for executing a line, tried in order.

@Psh::val

The default array where psh stores away the results of executing lines, as described in $Psh::echo above.

@Psh::wday ( Mon, Tue, Wed, Thu, Fri, Sat)

An array of the weekday names used in printing dates, for example in prompt strings.


PSH HASH VARIABLES

%Psh::array_exports

Contains a list of environment variables which should be tied to arrays. The key of the hash is the name of the variable, the value is the delimiter of the list (e.g. ':' in PATH). The default value for array_exports currently contains PATH, CLASSPATH, LD_LIBRARY_PATH, FIGNORE and CDPATH.

%Psh::built_ins

The keys are command names, the values do not matter. Builtins on this list may be autoloaded. This is initialized on startup by &Psh::Builtins::built_autoload_list();

%Psh::fallback_builtins

A list of fallback builtins Psh should provide. This currently defaults to ls and env.

%Psh::Strategy::Perlfunc::perl_builtins (by default, all Perl builtins and keywords)

The perlfunc evaluation strategy uses this hash on the first word of a command line to determine whether it should handle that command line. If the first word is present as a key in this hash, then the corresponding value determines the treatment: 0 means don't handle this line; any positive value means do handle the line as long as it has at least that many words. (Since the first word counts, a value of '1' will guarantee that the perlfunc strategy handles the line.) Useful for example to set $Psh::perl_builtins{grep} = 0; if you don't want ``grep'' to be treated as a perl function.

Note that the perlfunc strategy will also handle the line if the first word is not present as a key in this hash but a Perl subroutine of that name is defined.

%Psh::Strategy::Perlfunc::perl_builtins_noexpand (by default, Perl flow-control keywords)

The keys of this hash never have their arguments expanded in a shell-like fashion, even if $Psh::perlfunc_expand_arguments is true.

%Psh::prompt_vars

The keys of this hash are single characters, and the values are subroutine references that implement the given escape character in prompt strings. (See PROMPT STRINGS below.)

%Psh::strategy_which
%Psh::strategy_eval

These hashes implement the named strategies used in psh's evaluation of input lines. It is possible to add new strategies, see below.

%Psh::Completion::custom_completions

Allows you to add own TAB completions. The keys are names of programs to which the TAB completion should apply. The value is either a list reference with at least two values, up to three values, or a sub. If it's a sub it is called with the text to complete, text in front of the text to complete to the last whitespace and the word which triggered the completion.

The first element of the rules list is the character which should be appended after the completion is successful, the second value is again a list reference containing all possible completions. If the optional third value is true, the custom completion will replace all results of standard completions (like filename or username completion), if the value is false, the custom completion just adds additional results.

This is probably complicated but worth the effort.

Example:

%Psh::Completion::custom_completions = ( 'scp'=>['',['server1:/path1','server1:/path2','server2:/path']], 'foo'=>[' ',['bar','bla','fish'],1], 'hmm'=> sub { return ['/',['1','2','3'],1] } );


PSH FUNCTIONS

&Psh::evl

This function takes a string, evaluates it as if it were a line of psh input, and returns the value. Useful in loops like: psh$ for $file (glob $pat) { Psh::evl("ls -ld $file"); }

&Psh::is_number

Returns true if its first argument is a number. Intended for use in filter subroutines placed in $Psh::echo. For example, $Psh::echo = \&Psh::is_number; will cause only numeric return values to be printed.

&Psh::news

Returns the current news, as a string.

&Psh::Util::print_debug, print_error, print_out, print_warning

These four functions are called whenever psh wants to produce -d-mode output, error messages, normal output, and warnings, respectively. They could conceivably be redefined to implement logging or similar facilities.

&Psh::symbols

Takes one argument, a package name, and shows all of the symbols in that package.

There are other functions in the psh:: package, but they are probably not useful except internally to psh.

PROMPT STRINGS

Setting the variable $Psh::prompt to a string will cause that string to be used as the prompt-string. Setting it to a subroutine reference causes the result of running that subroutine to be used each time. For example,

  $Psh::prompt = sub { $i++; "psh [$i]\$ "; }

will cause the prompt to be psh [1]$ followed by psh [2]$, and so on.

psh uses some of the same ``prompting variables'' as bash. They are accessed by placing a backslash followed by the code in the prompt string, either hard coded, or as returned by the prompt string function. The variables supported are:

d The date in ``Weekday Month Day'' format
E The escape character
h The short hostname
H The long hostname
n A carriage return and line feed
s The name of the shell
t The current time in HH:MM:SS format
u The username of the current user
w The current working directory
W The basename of the current working directory
  • $ `#' if the effective UID is zero, else `$'
    [ ] Used for Term::ReadLine::Gnu to ignore control characters while determining the length of the prompt
  • Custom prompting variables may be added by adding entries to the array %Psh::prompt_vars keyed by the single character code. The entries should be subroutine references that return the replacement string.

    DEFINING EVALUATION STRATEGIES

    There are two hashes, %Psh::strategy_which and %Psh::strategy_eval. An evaluation strategy called ``foo'' is implemented by putting a subroutine object in each of these hashes keyed by ``foo''. The first subroutine should accept a reference to a string (the exact input line) and a reference to an array of strings (the array of ``words'' in the input line produced by &Psh::decompose, provided as a convenience so that each individual strategy doesn't have to recompute this). It should return a string, which should be empty if the strategy does not apply to that input line, and otherwise should be an arbitrary non-null string describing how that strategy applies to that line. It is guaranteed that the string passed in will contain some non-whitespace, and that the first string in the array of words is non-empty.

    The $strategy_eval{foo} routine accepts the same two first arguments and a third argument, which is the string returned by $strategy_which{foo}. It should do the evaluation, and return the result. Note that the $strategy_eval function will be evaluated in an array context.

    LIMITATIONS

    Due to limitations of the Win32 type of operating system there's no job control available on those systems.

    The loop inside psh will clobber $1 and other variables (including possible $_) because it uses matches to implement some of its special functions.

    Very little error checking is done. For example, if you evaluate !blork by the bang strategy and there is no command ``blork'' on your system, you get no feedback whatsoever.

    Right now, job control simply assumes that the POSIX interface is fully implemented. There should be a way to turn job control off if this is not the case.

    The ``exit status'' of programs invoked in the foreground by the ``executable'' strategy (or even the ``bang'' strategy) isn't available from within psh.

    Note that since expressions like 'use foo' return undef when sent to eval(), it is not possible to use that return value as indication of an error. Instead, we use the heuristic that there was no error unless the special Perl variable '$@' is non-empty. Note that the side effects of 'use foo' as a psh command line appear to be exactly as expected.

    Not exactly a psh limitation: Term::ReadLine::Gnu seems to be rather buggy on Linux systems and leads to continous crashes of psh. Use Term::ReadLine::Perl instead (set PERL_RL to ``Perl'' to disable Term::ReadLine::Gnu).

    REQUIREMENTS

    psh needs several optional Perl modules to offer full functionality:

    Term::ReadLine::Gnu or Term::ReadLine::Perl for readline support (command history, special editing chars etc.).
    Term::Size or Term::ReadKey to offer the ability to change the environment variables LINES and COLUMNS when the terminal window size changes while running as standard shell

    OTHER PERL SHELLS

    Larry Walls' Perl Shell

    Larry Wall exhibits the simple Perl shell while (<>) { eval; print $@; } on page 161 of the Camel Book (2nd Edition).

    lpsh

    Lee Eakin <leakin@dfw.nostrum.com> has written the Fancy Poor Man's Perl SHell (called lpsh for Lee's Perl Shell), a simple Perl shell that he has used for a number of years now (it is derived from Larry Wall's Perl Shell). He has added some numeric conversion functions because he often uses it as a calculator.

    He has placed it on the web at http://www.dfw.nostrum.com/~leakin/psh (for the code) and http://www.dfw.nostrum.com/~leakin/psh.README for a short explanation of the code and a reference to the main Perl Shell site.

    Perl Debugger Shell

    Rich Graves <rcgraves@brandeis.edu> posted a comment to the original psh-0.001 announcement on http://freshmeat.net, which contained this gem that leverages the Perl debugger: perl -d -e 1;

    perlsh

    Hiroo Hayashi <hiroo.hayashi@computer.org> includes perlsh, a ``one-line perl evaluator with line editing function and variable name completion function'' as an example with his Term::ReadLine::Gnu Perl module.

    PSH.pm

    In an example of convergent evolution, at http://jenda.krynicky.cz/ there is a Perl shell module called PSH.pm which is quite similar to this psh. It is designed to provide a command line that can be called inside some other program via PSH::prompt();, but a small file psh.pl is also included that uses PSH to provide a standalone shell. Perhaps some merger of these efforts would be beneficial to all?

    SoftList

    Some versions of the Perl faq mention an interactive Perl shell called SoftList, which can still be found at http://www.mit.edu/afs/sipb/contrib/perl/SoftList/. It predates Term::Readline and was apparently last touched in 1993, so it seems to be obsolescent.

    timtosh

    Tim Newsome, <nuisance@cmu.edu>, has developed a shell he calls timtosh (There Is More Than One SHell). Per his web site (http://www.wiw.org/~drz/timtosh), it is a shell written entirely in Perl. The goal is to get a shell which you can extend in Perl and can do some other niceties related to Perl (like perl re file matching). As of 1999-12-13 (Perl Shell 0.004 release date), Tim says timtosh ``is focused quite differently than psh is, but is currently still waiting for a rewrite of the command line parsing. (It has been for almost a year now)''.

    vbsh

    Tom Christiansen and Nathan Torkington's book Perl Cookbook, published by O'Reilly in 1998 (ISBN 1-56592-243-3) has ``Example 15-4. vbsh'' on page 531 for section 15.11 (Editing Input). It stands for Very Bad SHell.

    Comparison of perl shells

    As an aid to comparing/contrasting these different shells, here is a brief table indicating whether or not each has certain features.

      Key to features:
        PE : Perl evaluation of Perl expressions
        SHE: shell-like evaluation of shell-like expressions, including 
             'exec'ing executables searched for in PATH
        CLE: command-line editing
        JC : job control
        PL : pipelines 
    

      Key to symbols:
        * : feature present
        - : feature absent
        ? : don't know 
    

      The shells:
    

        Shell Name         PE    SHE   CLE    JC    PL
    

     psh (this one)         *     *     *     *     *            
     Larry Wall shell       *     -     -     -     -
     lpsh                   *     -     *     -     -
     Perl debugger shell    *     -     *     -     -
     perlsh                 *     -     *     -     -
     Krynicky PSH.pm        *     *     ?     -     ?
     SoftList               *     ?     *     ?     ?
     timtosh                -     *     *     *     *
     vbsh                   ?     ?     ?     ?     -
    

    ENVIRONMENT VARIABLES

    CDPATH - A list of paths of directories in which the cd builtin should search for its argument. Defaults to ``.''.

    FIGNORE - A list (separated by the path separator) of file endings to ignore when performing TAB completion. No default.

    HISTSIZE - The maximum number of lines to save in the history file. Defaults to 50.

    LANG - Sets the language of the shell.

    SHLVL - The number of shells deep that psh is nested. Initially set to 1. Many other shells do not increment this variable, so it is not authoritative.

    PS1 - If $Psh::prompt is unset, psh will try to use this environment variable as prompt.

    PS2 - If $Psh::prompt_cont is unset, psh will try to use this variable as continuation prompt.

    PSH_TITLE - If $Psh::window_title is unset, psh will try to use this variable as window title.

    USER - The name of the current user

    FILES

    psh - The Perl Shell executable script.

    .pshrc - The user's Perl Shell `profile'. May be in $HOME or the current directory; if both are present, both will be read in the order mentioned.

    AUTHOR

    Gregor N. Purdy, <gregor@focusresearch.com>

    CREDITS

    The following people have contributed to the development of psh:

    Prodigious Contributors

    Markus Peter <warp@spin.de> added job and signal handling, globbing, redirection, pipelines, completion code, Win32 port, i18n code, bash compatibility builtins and environment variables and some more minor updates.

    Glen Whitney <gwhitney@post.harvard.edu> added evaluation strategies, improved interrupt/job handling, &Psh::evl, $Psh::echo, more extensive documentation, and other more minor features.

    Omer Shenker <oshenker@iname.com> added file locking, Win32 code, login shell handling, various bits of documentation, and other minor features and updates.

    ReadLine Support

    Code examples showing how to apply the Term::ReadLine package were contributed by Billy Naylor <billy.naylor@eu.net> (in his pash.pl program, which is his own Perl shell).

    Symbol Table Dumping

    Billy Naylor <billy.naylor@eu.net> also had an example of a symbol table printing function that was used as the starting point for the psh function psh::symbols(). The psh version adds the ability to specify a package name, and it also filters out some special variables. The implementation technique is also different from Billy's.

    Prompt String Variables

    Matthew D. Allen <s2mdalle@titan.vcu.edu> contributed an enhanced prompt string handling routine that emulates the bash prompt variables. This was expanded into the form now present.

    Typo Spotting

    Allan Kelly <akelly@holyrood.ed.ac.uk> found some problems with the generated documentation.