tags:

views:

86

answers:

5

I am trying to do something like this

 ruby test.rb | source /dev/stdin

where test.rb just prints out cd /. There are no errors, but it doesn't do anything either. If I use this:

 ruby test.rb > /tmp/eraseme2352; source /tmp/eraseme2352

it works fine, but I want to avoid the intermediate file.

Edit: The whole point of this is that the changes need to persist when the command is done. Sorry I didn't make that clearer earlier.

A: 

How about just

ruby test.rb | bash
Matti Virkkunen
This will execute the commands in a subshell. Any side-effects like changing directories or setting environment variables will be lost.
Thomas
Indeed it will. Not using a subshell wasn't exactly listed as a requirement... the $() syntax seems much nicer though.
Matti Virkkunen
It's kind of implied as a requirement given the example code.
Yar
+2  A: 

Until a more experienced bash hacker comes along to correct me, you could do this:

for c in `ruby test.rb` ; do $c ; done

Caution: This doesn't do what you want. Read the comments!

Thomas
That could be useful, too. Thanks.
Yar
This will treat each 'word' (blank separated tokens) in the output of the Ruby script as a command. If no commands have arguments, it will work. If any command has arguments, it will not work.
Jonathan Leffler
The problem is that this is the problem I'm trying to avoid: learning shell scripting. Is there any way for me to format my output so as to make it work for multiple lines? What I really want to do is `| source`
Yar
@Jonathan: Argh, whoops. I'd only tested with simple commands. Will leave it here with a warning.
Thomas
+4  A: 

you can try:

$(ruby test.rb)

$(...) tells bash to execute whatever output is produced by command inside ().

mouviciel
That rocks and solves heaps of problems.
Yar
While we're here: is there any way to get the shell to NOT show the commands as they're being run?
Yar
Beware that this only works if the Ruby script outputs just a single command line. If it spits out multiple lines, they will all be joined together into one big command.
Thomas
@Thomas, oh, didn't think of that. I'll unmark this as best answer for now hoping to get a better best answer.
Yar
@Thomas, actually that's not true. Not sure why, but in trying it with multiple lines it works perfectly.
Yar
@yar: If it works for you, great. But `$(echo -e 'ls\ncd')` gives me `ls: cannot access cd: No such file or directory`. A quick scan through the bash manpage shows that it might have to do with the value of `IFS`.
Thomas
@Thomas, not sure what's going on. Your test failed for me too, yet this `tell app "Terminal" to do script "$(paste_env)" ` works and the results is many lines of code. Something tricky here, not sure.
Yar
+2  A: 
eval `ruby test.rb`
Andrew Medico
Why would you need the `eval`?
Thomas
@Thomas: because, for example, `eval $(echo 'var1=27;var2=38')` works as expected sets those variables in the current shell. Without the `eval`, it's executed as one command and gives an error: "var1=27;var2=38: command not found".
Dennis Williamson
The plot thickens, cool!
Yar
@Dennis Williamson: are the backticks equivalent to the `$()`? Then I should mark this one as best answer, seems?
Yar
@yar: They are mostly equivalent, but `$()` is [preferred](http://mywiki.wooledge.org/BashFAQ/082).
Dennis Williamson
+1  A: 

bash (not sh):

while read -a line
do
  "${line[@]}"
done < <(somescript)

Spaces in arguments to commands will need to be backslash-escaped in order to work.

Ignacio Vazquez-Abrams
nice, thanks, but I think I might go with `eval $()` as a best answer.
Yar