如何从ruby脚本中的(终端)cd文件夹中

时间:2022-06-29 20:23:29

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

我想知道是否可以从我执行ruby脚本的位置更改当前的终端目录。

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.

例如,如果我在终端中从$ HOME执行脚本,我想在脚本末尾cd $ HOME / mydir。

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.

我在SO中发现了类似的东西,但它与Python相关并且响应似乎是否定的。


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:

我目前参与了一个命令行应用程序(使用gli),作为起点,需要一个项目文件夹。所以我的第一个命令看起来像:

$ 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:

这会在当前目录中创建一个名为project的新文件夹。现在能够使用我需要的其他命令:

$ 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.

所以我只是觉得在执行myfoo新项目之后在项目中找到自己会很好。


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?

我害怕,这并不容易(根本不可能)。那么使用一个执行我想要的ruby调用的bash脚本来代替RubyGems生成的标准文件呢?这可行吗?我傻了吗?我应该使用eval吗?


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

谢谢你的回答。但我担心没人接受。可能问题不是:)。

4 个解决方案

#1


2  

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.

据我所知,这是不可能的,因为它们是不同的过程。如果你需要影响Ruby脚本的父进程(Bash),Bash需要提供一些东西。所以你可以让你的Ruby脚本输出一些bash命令,然后有一个Bash包装器来源Ruby的输出。

Try this as an example, in Bash:

以Bash为例,试试这个例子:

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

But this will only work in Bash 4.0.

但这只适用于Bash 4.0。

EDIT:

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

实际上,您可以使用eval而不是Bash 3中的源来执行此操作:

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

#2


2  

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.

当你从登录shell启动一个程序时,它正在做一个fork / exec,这意味着创建了一个新的(子)进程(它有自己的环境,比如当前的工作目录),它是标准的输入/输出/错误流与(父)shell进程相关联。因此,当您的脚本调用Dir.chdir时,它会更改脚本(子)进程的当前工作目录,而不是父进程。

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...

也许你的脚本可以在它退出之前启动一个新shell,所以看起来你的终端已经改变了目录。虽然,在退出终端会话之前,您必须退出该额外的shell ...

#3


1  

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与Maerics结合使用,以便在ruby中创建一个新的bash shell来实现这一点。

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).

exec将使用子进程(ruby)替换父进程(shell),因此shell不再存在(无需退出)。

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.

在ruby例程结束时,bash在新目录中被激活(再次使用exec这次在ruby中)并替换ruby进程。

#4


0  

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

Midnight Commander通过使用shell别名和包装脚本来完成此操作。

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.

包装器用于cd到由出口处由mc(1)写入的文件内容确定的目录,并且别名用于获取包装器,这使得它在登录shell中执行,而不是在子shell中执行如果脚本正常启动,它会被分叉。

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.

为此,您需要复制别名/包装器功能。请参阅http://midnight-commander.org/browser/contrib了解他们是如何做到的。

#1


2  

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.

据我所知,这是不可能的,因为它们是不同的过程。如果你需要影响Ruby脚本的父进程(Bash),Bash需要提供一些东西。所以你可以让你的Ruby脚本输出一些bash命令,然后有一个Bash包装器来源Ruby的输出。

Try this as an example, in Bash:

以Bash为例,试试这个例子:

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

But this will only work in Bash 4.0.

但这只适用于Bash 4.0。

EDIT:

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

实际上,您可以使用eval而不是Bash 3中的源来执行此操作:

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

#2


2  

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.

当你从登录shell启动一个程序时,它正在做一个fork / exec,这意味着创建了一个新的(子)进程(它有自己的环境,比如当前的工作目录),它是标准的输入/输出/错误流与(父)shell进程相关联。因此,当您的脚本调用Dir.chdir时,它会更改脚本(子)进程的当前工作目录,而不是父进程。

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...

也许你的脚本可以在它退出之前启动一个新shell,所以看起来你的终端已经改变了目录。虽然,在退出终端会话之前,您必须退出该额外的shell ...

#3


1  

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与Maerics结合使用,以便在ruby中创建一个新的bash shell来实现这一点。

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).

exec将使用子进程(ruby)替换父进程(shell),因此shell不再存在(无需退出)。

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.

在ruby例程结束时,bash在新目录中被激活(再次使用exec这次在ruby中)并替换ruby进程。

#4


0  

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

Midnight Commander通过使用shell别名和包装脚本来完成此操作。

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.

包装器用于cd到由出口处由mc(1)写入的文件内容确定的目录,并且别名用于获取包装器,这使得它在登录shell中执行,而不是在子shell中执行如果脚本正常启动,它会被分叉。

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.

为此,您需要复制别名/包装器功能。请参阅http://midnight-commander.org/browser/contrib了解他们是如何做到的。