Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hello Monks,
I'm writing a Tk entry that emulates term:
open(COM,"$run_cmd 2>&1 |") || die "Could not execute command\n";
$_ = <COM>;
do{
$txt -> insert('end',$_);
}
while(<COM>);
close(COM);
$txt->see('end');
$txt_2->see('end');
$cmd_entry->delete('0.0', 'end');
ruuning the command "ls -l *" will work just fine
, but when Im trying to run "l" which is an alias for "ls -l *" it is not recognized. how do I pass my environment setup through the pipeline. Thanks in advance dear Monks. Michael

Replies are listed 'Best First'.
Re: passing setup via pipeline
by Corion (Patriarch) on May 25, 2010 at 07:17 UTC

    Shell aliases do not work, because system does not (always) invoke the shell. You will need to explicitly invoke the shell if you want shell aliases to work.

      As an addition to Corion's comments, it also depends on where your alias is specified, and which shell you are using. Even if system does invoke a shell it will be a Bourne shell (/bin/sh -c). So if, for example, your aliases are defined in ~/.kshrc then that will not be read. If you invoke your shell explicitly then you should carefully note which startup files are executed for non-login non-interactive sessions. For example, Korn shell 88, Korn shell 93, and Bash all have different rules for that.

      Personally I would discourage use of aliases anywhere except as an interactive keyboard productivity aid - they are a support nightmare when used in scripts.
      hmmm

      I was thinking to use another pipeline, for example:
      open(MYPIPE,"source .aliases|");
      my $mypipe = <MYPIPE>;
      open(COM,"$mypipe | $run_cmd 2>&1 |") || die "Could not execute command\n";

      $_ = <COM>;
      do{
      $txt -> insert('end',$_);
      }

      while(<COM>);
      close(COM);


      what do you think, does it have a chance
      BR
      Michael
        First, 'source' is a c-shell or bash built-in, so you need to specify the shell.
        Second, that would just create the aliases in one child process. The second open will run a different process without the aliases.

        I think you want open3 or similar.

        open3(*TO_CHLD, *FR_CHLD, undef, 'bash')

        Then you can print out commands to TO_CHLD and collect the output from FR_CHLD. Then you can issue shell commands including aliases, and the state of the shell (incl current work dir and environment settings) will persist between commands.

        Hum, actually, you would need a pty instead of a pipe to get interactive behaviour. IPC::Run can do all of this pretty easily, so it's probably a better choice than open3

        Your idea does not make any sense to me.

Re: passing setup via pipeline
by almut (Canon) on May 25, 2010 at 10:19 UTC

    Presuming your aliases are defined in .aliases (and in bourne shell compatible syntax), this should work:

    my $run_cmd = 'l'; open(COM, ". .aliases\n$run_cmd 2>&1 |") || die "Could not execute com +mand\n"; ...

    Note that there must be a newline (not a semicolon) after sourcing the .aliases file, because aliases cannot be used on the same line that they are defined.

    P.S.: not all shells will by default expand aliases, unless in interactive mode. For example, sh does, while bash does not (even if sh is just a symlink to bash), but you can explicitly enable the feature via shopt -s expand_aliases.  Hence, the above example only works because perl calls /bin/sh -c behind the scenes (at least typically — check with perl -V:sh).

      Hi all,
      This is something I wanted to avoid, since it is a preaty heavy setup.
      So I don't want to run it per each command I perform.
      At any case, you've been a great help!
      Thank U monks!

      Michael - du lak