Emiliano Poggi
Emiliano Poggi

Reputation: 24836

How to (terminal) cd in folder from ruby script

I'd like to know if it's possible to change the current terminal directory from where I'm executing my ruby script.

For example, if I'm executing the script from $HOME in the terminal, I would like to cd in $HOME/mydir at the end of the script.

I've tried a couple of things, but I'm always finding in the same directorry where the script was started.

Things I've tried:

Dir.chdir( mydir )
%[cd mydir]

They actually do change directory, but only in the thread of the script execution. When the script ends, my current location in the terminal is still the same I was before launching the script.

I've found something similar in SO, but it's Python-related and response seems negative.


You may ask why?

I'm currently involved in a command line application (using gli) which, as starting point, needs a project folder. So my first command looks like:

$ myfoo new project

Which creates a new folder with name project in the current directory. Now to be able to work with the other commands I need to:

$ cd project
project$ myfoo domore

So I was simply thinking that it would be nice to found my self in project after having executed myfoo new project.


As I was afraid, it's not that easy (not possible at all). So what about using a bash script which does the ruby calls that I want, in place of the standard file generated by RubyGems? Is that feasible? Am I foolish? Should I use eval?


Thanks for the answers. But I'm afraid that no one is acceptable. Probably the question wasn't :).

Upvotes: 8

Views: 3176

Answers (4)

diedthreetimes
diedthreetimes

Reputation: 4113

Maybe slightly easier,

You can use exec in combination with Maerics post about creating a new bash shell inside of ruby to achieve this.

exec ruby -e "Dir.chdir( 'mydir' ); exec 'bash'"

exec will replace the parent process(shell) with the child process (ruby), thus the shell no longer exists (no need to exit).

At the end of the ruby routine bash is fired up (again with exec this time in ruby) in the new directory and replaces the ruby process.

Upvotes: 1

kvs
kvs

Reputation: 1

Midnight Commander does this, by using a shell alias and a wrapper-script.

The wrapper is for cd'ing to a directory determined by the contents of a file written by mc(1) at exit, and the alias is used to source the wrapper, which makes it execute in the login shell, instead of the subshell that would have been forked, had the script been launched normally.

All in all, this lets it change the current working directory on exit.

To do this, you'd need to duplicate the alias/wrapper functionality. See http://midnight-commander.org/browser/contrib for how they did it.

Upvotes: 0

maerics
maerics

Reputation: 156642

I doubt there is a straightforward way to do this.

When you launch a program from your login shell, underneath the hood it's doing a fork/exec which means a new (child) process is created (which has its own environment, such as current working directory) and it's standard input/output/error streams are associated with the (parent) shell process. So when your script calls Dir.chdir it changes the current working directory for the script (child) process, not the parent.

Perhaps your script could launch a new shell before it exits, so it looks like your terminal has changed directory. Although, you'd have to exit from that extra shell before exiting your terminal session...

Upvotes: 2

Ian
Ian

Reputation: 2108

This isn't possible, to my knowledge, since they're different processes. If you need to affect the Ruby script's parent process (Bash), Bash will need to source something. So you could have your Ruby script output some bash commands, then have a Bash wrapper that source's Ruby's output.

Try this as an example, in Bash:

`ruby -e 'puts "cd /tmp"'` | source /dev/stdin

But this will only work in Bash 4.0.

EDIT:

Actually, you can do this with eval instead of source in Bash 3:

eval $(ruby -e'puts "cd /tmp"')

Upvotes: 2

Related Questions