http://www.perlmonks.org?node_id=542636

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

I've been trying to determine if it is possible to specify a shell or shell variables and parameters for perl. The issue that I have is that there are specific environment variables and parameters that need to be set in a .csh environment (ex. PATH). When using the backticks like `myscript` it is instantiating a new shell and applying any environmental variables from the .cshrc which is overwriting the needed environmental variables.

The underlying reason for doing this is that there are several commands such as cp, cd, uname, etc that I need to use alternate versions while using an NFS mounted file system that cannot handle several special cases such as hard/soft links in a UNIX style fashion, and special code needs to be called to handle these kinds of issues. Unfortunately when trying to use `cp` in perl I am getting the wrong version since the PATH is coming from the newly instantiated csh and not from the enviroment that perl is running in.

I believe that the standard practice to get csh to do a 'fast' login is to use the -f switch and then it will avoid loading up the .cshrc and thus wouldn't overwrite the currently setup environment and variables.

Is there any variable or parameter in perl that can be set to tell it for example to use "csh -f" for the enviroment, or perhaps set it to "ksh" or "bash" for the shell? I've tried looking through all the docs, and while I believe system called through a multi parameter mode would avoid the shell (and probably do what I want) it only returns a status code of the program run and not the actual contents. Having to pipe the output to a file and then reading that in is perhaps a bit more complicated than the intended fix.

Thanks in advance for any hints or clues that may help me out here!

  • Comment on Specifying a shell for use with Backticks

Replies are listed 'Best First'.
Re: Specifying a shell for use with Backticks
by zentara (Archbishop) on Apr 11, 2006 at 20:01 UTC
    I know you asked about backticks, but an alternative would be to use IPC::Open3, then you could specify whatever shell you want to run your script.
    #!/usr/bin/perl use warnings; use strict; use IPC::Open3; $|=1; #my $pid=open3(\*IN,\*OUT,\*ERR,'/bin/bash'); my $pid=open3(\*IN,\*OUT,0,'/bin/bash'); # set \*ERR to 0 to send STDERR to STDOUT my $cmd = 'date'; #send cmd to bash print IN "$cmd\n"; #getresult my $result = <OUT>; print $result;

    I'm not really a human, but I play one on earth. flash japh
Re: Specifying a shell for use with Backticks
by derby (Abbot) on Apr 11, 2006 at 19:27 UTC

    There's no way of overriding backtick (or qx) that I know of ... and by default it should be using some bourne shell variant not csh (but I guess it all depends on what type of wackiness your system was in when perl was built - I've seen plenty of systems where sh was really csh). I think you're going to be better off with fork and exec -- modified from the code in perlsec:

    #!/usr/bin/perl use English '-no_match_vars'; my $content = mysystem( "/bin/ls", "-l" ); print $content; sub mysystem { my @args = @_; my $pid; my $content; die "Can't fork: $!" unless defined($pid = open(KID, "-|")); if( $pid ) { # parent while (<KID>) { $content .= $_; } close KID; $content; } else { my @temp = ($EUID, $EGID); my $orig_uid = $UID; my $orig_gid = $GID; $EUID = $UID; $EGID = $GID; # Drop privileges $UID = $orig_uid; $GID = $orig_gid; # Make sure privs are really gone ($EUID, $EGID) = @temp; die "Can't drop privileges" unless $UID == $EUID && $GID eq $EGID; $ENV{PATH} = "/bin:/usr/bin"; # Minimal PATH. # Consider sanitizing the environment even more. exec @args or die "can't exec: $!"; } }
    Since no shell is being used, just ensure you have your environment the way you want before calling the code (and please beef this sample up ... it does no error checking nor return value checking).

    -derby
Re: Specifying a shell for use with Backticks
by fletcher_the_dog (Friar) on Apr 11, 2006 at 19:23 UTC
    You can specify enviornment variables for commands done in backticks by using the special %ENV hash, like this
    $ENV{FRED}="JONES"; # this will print JONES print `echo \$FRED`;
Re: Specifying a shell for use with Backticks
by merlyn (Sage) on Apr 11, 2006 at 20:16 UTC
Re: Specifying a shell for use with Backticks
by hacker (Priest) on Apr 11, 2006 at 20:09 UTC
Re: Specifying a shell for use with Backticks
by Zerhash (Scribe) on Apr 11, 2006 at 19:18 UTC
    you could read the .profile for the path and set it in the perl script. or before you execute you can export the path variable
Re: Specifying a shell for use with Backticks
by Argel (Prior) on Apr 11, 2006 at 22:41 UTC
    A kludge would be something like `/usr/bin/tcsh -c myscript`.
Re: Specifying a shell for use with Backticks
by Anonymous Monk on Apr 12, 2006 at 00:33 UTC
    I am not really a power perl user but mostly shell user. But I think the following idea will work. Assuming that your "myscript" is indeed a cshell script Try using #! /bin/csh -f as the first line in that file. Also Try reading "UNIX power Tools by Jerry Peek, Tom O'Reilly, Chapter 47 "Shell Programming for ..." 47.02 - 47.05 the story of #! to get good handle on what shell get's used when you invoke a script. Good luck --- Rama Reddy ( Rama.Reddy@intel.com )
Re: Specifying a shell for use with Backticks
by gaspodethewonderdog (Monk) on Apr 12, 2006 at 13:01 UTC
    First I want to thank everybody for the comments.

    We know for certain that it is picking up the .cshrc settings because when we remove the PATH statements all of the alternate commands are working properly, and hence my assumption that they are using csh when backticking commands in perl. Unfortunately some of the people here running the perl scripts need to have both special PATH and ENVIRONMENT settings for the perl tools as well as other tools, and they both conflict with each other. It is very much a chicken and egg problem.

    Since we are getting both sets of tools from a corporate source repository, and we really are not at liberty to make changes to them that is why I was just hoping for a quick one change of code to change the backtick behavior that I could send of to HQ and hope that it would get implemented some day. Even though using the IPC modules is a good alternative, I doubt I'll be able to get somebody to change the implementation under the hood of these scripts.

    Again, thank you all for posting. Even though I cannot do much in this case I will definitely check out IPC::Open3 and IPC::Run at least for my own scripts. Given how touch and go the environment is here I don't want to be adding to this very huge mess.

      If you really can't get backticks to use a reasonable shell, perhaps you can trick it. For example in ksh, you can do something like this...

      my $output = `PATH=$ENV{PATH} command arg1 arg2 argn`;

      ... which sets PATH just for the command. Just be careful you know what is in $ENV{PATH} (e.g. no spaces; not user supplied). I don't know if this syntax will work for csh also, so perhaps something ugly like...

      my $output = `setenv PATH "$ENV{PATH}"; command arg1 arg2 argn`;

      An alternative, if you are only worred about the PATH, might be to supply a fullpath to backticks (i.e. dont give the shell a chance to locate it - just tell it)...

      my ($cp) = grep { -x $_ } map { "$_/cp" } grep { length $_ } split /:/ +, $ENV{PATH}; die "cant find cp" unless defined $cp; my $output = `$cp source dest`;

      IMO these seem like band-aids for the real problem. Using csh is just unsafe, outside of an interactive shell.

Re: Specifying a shell for use with Backticks
by bigmacbear (Monk) on Apr 12, 2006 at 17:20 UTC

    I had a similar problem with a Makefile a long time ago. Make used whatever shell was in the user's environment rather than defaulting to a /bin/sh-like shell, and everybody used /bin/csh at the site. So I had to explicitly set $SHELL to /bin/sh in the Makefile.

    Extrapolating to Perl, have you tried explicitly setting $ENV{'SHELL'}=/bin/sh before running your backticks?

Re: Specifying a shell for use with Backticks
by mattr (Curate) on Apr 14, 2006 at 14:48 UTC
    Just a shot in the dark but when you build perl, doesn't it ask you your preference, i.e. "Where is your preferred shell program?" In which case you could build another perl for your app. Sorry if this doesn't help though. I suppose you tried calling /bin/sh from inside the backticks but had trouble getting the result returned?