6

suppose you have a perl script "foobar.pl" that prints the following to stdout

date -R

and you want to run whatever that perl script outputs as a standalone bash command (don't worry about security problems as this is running in a trusted environment).

How do you get bash to recognize this as a standalone command?

I've tried using xargs, but that seems to want to pass arguments only to a pre-defined command.

I want the perl script to be able to output any arbitrary command.

$command = 'date -R'
system($command); ## in the perl script 

the above does not work because I want it to run in an existing cygwin environment ...

foobar.pl | xargs bash -i {}

the above does not work because bash seems to be running a new process and thus the initialization and settings from bash_profile don't get instantiated.

dreftymac
  • 31,404
  • 26
  • 119
  • 182

6 Answers6

5
`foobar.pl`
Brian Campbell
  • 322,767
  • 57
  • 360
  • 340
4

Given the perl file:

print "date";

the following bash command will do it.

> $(perl qq.pl)
Mon Apr  6 11:02:07 WAST 2009

But that is run in a separate shell. If you really want to invoke it in the context of the current shell, do this:

$ perl qq.pl >/tmp/qq.$$ ; . /tmp/qq.$$ ; rm -f /tmp/qq.$$
Mon Apr  6 11:04:59 WAST 2009
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • In the $() case, the command "perl qq.pl" is run in a separate shell, but the command returned by it, "date", is run in the current shell, which is, I think, what he wanted. – Brian Campbell Apr 06 '09 at 03:09
  • You shouldn't be using `.` or `source` to run the commands. You never know what the script will do to your running shell; which means you cannot rely on the fact that you'll even get the chance to do your temp file cleanup properly. Putting the cleanup in a trap on EXIT might help with that. – lhunath Apr 06 '09 at 07:13
  • @lhunath, did you not read the question? Quoth the raven "don't worry about security problems as this is running in a trusted environment". I took that to mean the output of the Perl script was controlled. And the use of "." was specifically to meet the requirement it not start a new process. – paxdiablo Apr 06 '09 at 07:47
4

Bad:

`perl foo.pl`
$(perl foo.pl)

Why is this bad? Because of so many reasons; most notably:

  • Wordsplitting: What you're doing here is taking the output of the perl script, splitting it into chunks wherever there are spaces, tabs or newlines, and taking those chunks as arguments to the first chunk which is the command to run. In really extremely simplistic cases like $(echo 'date +%s') it might work; but that's just a really bad representation of what you're REALLY doing here.
  • You cannot do quoting or use any other bash shell features like parameter expansion, bash keywords, etc.

Good, but inconvenient:

perl foo.pl > mytmpfile; bash mytmpfile

Creating a temporary file to put your perl script's output into and then running that with bash works, but it's inconvenient as you need to create (and clean up!) your temporary file and have it in a portably writable (and secure!) location.

Also remember not to use . or source to execute the temporary file unless you really intend to run it all in the active shell. Moreover, when you use . or source, you won't be able to reliably clean up your temporary file afterward.

Probably the best solution:

perl foo.pl | bash

This is pretty safe all-round ("safe" in the context of, least bug-prone) assuming your perl script outputs correct bash syntax, of course.

Alternatives that do pretty much the same thing:

bash < <(perl foo.pl)
bash <(perl foo.pl)
lhunath
  • 120,288
  • 16
  • 68
  • 77
  • bash <($OUTPUT) is what I was looking for. It makes a HUGE difference with piping as you still have the control of it - for inputs. – yclian Aug 09 '10 at 18:53
3

Try:

foobar.pl | bash
j_random_hacker
  • 50,331
  • 10
  • 105
  • 169
0

I don't think this is exactly what you're looking for, but its what I've got :-)

perl foo.pl > /tmp/$$.script; bash /tmp/$$.script; rm /tmp/$$.script

Good luck!

Bennett Dill
  • 2,875
  • 4
  • 41
  • 39
0

Try with open($fh,"-|",$arg1,$arg2)