【问题标题】:How to (terminal) cd in folder from ruby script如何(终端)从 ruby​​ 脚本的文件夹中 cd
【发布时间】:2011-09-02 03:50:40
【问题描述】:

我想知道是否可以更改我正在执行我的 ruby​​ 脚本的当前终端目录。

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

我已经尝试了几件事,但我总是在启动脚本的同一个目录中找到。

我尝试过的事情:

Dir.chdir( mydir )
%[cd mydir]

他们实际上确实改变了目录,但只是在脚本执行的线程中。当脚本结束时,我在终端中的当前位置仍然与启动脚本之前相同。

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


你可能会问为什么?

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

$ myfoo new project

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

$ cd project
project$ myfoo domore

所以我只是认为在执行myfoo new project 之后在project 中找到自己会很好。


正如我所担心的那样,这并不容易(根本不可能)。那么使用 bash 脚本来执行我想要的 ruby​​ 调用来代替 RubyGems 生成的标准文件呢?这可行吗?我傻吗?我应该使用eval吗?


感谢您的回答。但恐怕没有人可以接受。可能问题不是:)。

【问题讨论】:

  • 您似乎不太可能做到这一点。来自 ruby​​ 的任何系统调用都在与您的脚本/shell 不同的线程中运行,并且对当前位置没有影响。你希望用它做什么?
  • @Douglas-F-Shearer:我在答案中稍微扩展了我的理由
  • 只是出于好奇,为什么我的答案不起作用?我已经使用过这种技术几次,但我不清楚它为什么不适合您的情况。
  • @Ian:您的回答有效,但不适用于我的情况。我有五个命令(将来可能会更多),我想继续使用rubygem。我应该在命令执行级别整合东西(参见new 命令here

标签: ruby


【解决方案1】:

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

在 Bash 中试试这个作为示例:

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

But this will only work in Bash 4.0.

编辑:

实际上,您可以在 Bash 3 中使用 eval 而不是 source 来做到这一点:

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

【讨论】:

  • 好的,但我的脚本以%[eval $(ruby -e'puts "cd /tmp"')] 结尾,这没有任何区别。
  • 对,因为您正在生成一个子 Bash 进程(您想要影响的 Bash 进程的孙子进程),在其中评估您的代码,然后让它死掉。您需要在要更改的 Bash 进程中直接运行 eval。稍后,您可以使用别名或其他东西来整理它。
  • 我已经扩展了反过来问问题的答案。
  • 仍然需要从当前的 bash 进程中调用 source。你无法解决这个问题。所以,你可以有一个看起来像 eval $(ruby my_script_that_outputs_bash.rb) 的 bash 脚本,你可以把它叫做 source my_script_that_evals.sh
【解决方案2】:

我怀疑是否有一种直接的方法可以做到这一点。

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

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

【讨论】:

  • 我已经扩展了反过来问问题的答案。
【解决方案3】:

也许稍微容易一点,

您可以将 exec 与 Maerics 的帖子结合使用,以在 ruby​​ 中创建新的 bash shell 来实现此目的。

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

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

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

【讨论】:

  • 如何将其与具有自己命令的 ruby​​gem 集成,就像答案中描述的那样?
  • @empo 在 ruby​​ 脚本的最后添加 exec 'bash'。在命令行中,将调用修改为 exec myfoo new project。不过这仍然很笨重:(
【解决方案4】:

Midnight Commander 通过使用 shell 别名和包装脚本来做到这一点。

包装器用于 cd'ing 到由 mc(1) 在退出时写入的文件内容确定的目录,别名用于 source 包装器,使其在登录 shell 中执行,如果脚本正常启动,而不是分叉的子shell。

总而言之,这让它在退出时更改当前工作目录。

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

【讨论】:

  • 是否有相关文档?如何将它应用到我的用例中?
  • 这和我的回答是一样的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-04-10
  • 2020-09-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-18
  • 1970-01-01
相关资源
最近更新 更多