在 Ruby 脚本中执行 cd 命令

5
我想在Ruby脚本中更改当前shell的密码。因此:
> pwd
/tmp
> ruby cdscript.rb
> pwd
/usr/bin

这是我目前拥有的代码:

exec('cd /usr/bin')

很遗憾,cd是一个内置命令。所以:

`exec': No such file or directory - cd (Errno:ENOENT)

有没有什么解决办法?


无法直接在ruby中实现,所以我改变了方向。我修改了脚本以输出目标目录路径,并在.bashrc中定义了一个函数,该函数将参数通过脚本传递,然后cd到正确的目录。虽然不是我希望的自包含形式,但它完成了工作。

感谢大家的回复。


你可以在你的 Ruby 代码中尝试 cd /usr/bin 或者 system('cd /usr/bin'),但这只会改变新 shell 的当前目录(它是 Ruby 的子进程,而 Ruby 又是 shell 的子进程),但这是无意义的,因为我认为你不能在 *inx 系统中更改父进程的目录。 - jcubic
那么如何使用shell解决方案呢?比如在bash配置文件中加入“alias usb="cd /usr/bin"”,然后在shell中键入“usb”。 - Nikita Rybak
有一堆代码逻辑需要到达执行部分(实际上不仅仅是静态路径)。这只是一个微不足道的例子,因此别名不是最佳选择。 - Joe Mastey
一个可以改变当前工作目录(因此,可能会影响大量环境变量)的脚本难道不应该被视为严重的安全隐患吗?这就是为什么即使有“信任”机制,.rvmrc 也让我感到紧张的原因。 - saurabh
7个回答

14

Dir.chdir("/usr/bin")会在Ruby脚本中更改当前工作目录,但是这不会更改父进程(也就是shell)的PWD,因为脚本在子进程中执行。


3
这取决于你怎么看,他试图执行'cd'时遇到了问题,而这也永远不会起作用。如果他询问为什么Dir.chdir()不起作用,那么这个答案就完全无关紧要了。无论如何,为了完整性进行了编辑。 - Vinko Vrsalovic
2
@sepp2k:这正是我在寻找的答案,它运行得非常好,感谢Vinko。 - Dorian

8
你无法更改你的 shell 的工作目录。
当执行 Ruby 时,它会分叉出一个新的环境,并设置一个新的工作目录。

6

在搜索如何做同样的事情时,我偶然发现了这个方法。

我通过在反引号中运行多个语句来解决这个问题。

'cd #{path} && <statement> && cd ..'

4

正如其他答案已经指出的那样,您可以在Ruby脚本内部更改pwd,但这只影响子进程(即您的Ruby脚本)。父进程的pwd无法从子进程中更改。

一个解决办法是让脚本输出要执行的shell命令,并在反引号中调用它(即shell执行脚本并将其输出作为要执行的命令)

myscript.rb:

# … fancy code to build somepath …
puts "cd #{somepath}"

调用它:

`ruby myscript.rb`

通过使用别名将其变成简单的命令:

alias myscript='`ruby /path/to/myscript.rb`'

不幸的是,这种方式无法让您的脚本向用户输出文本,因为脚本输出的任何文本都会被shell执行(尽管还有更多的解决方法)。


0

在 Ruby 脚本(或任何其他类型的应用程序)中,您无法更改调用您的 shell 的工作目录(或环境变量)。唯一能够更改当前 shell pwd 的命令是 shell 内置命令。


0

你可以尝试使用system代替exec。 这对我很有效。

例如:system("cd #{new_path} && <statement> && cd #{original_path}")


0

正如其他答案所指出的那样,在Ruby脚本中运行system("cd foo")`cd foo`只会更改Ruby子进程的目录。一旦Ruby脚本完成,您将返回到之前所在的目录。

解决这个问题的方法是让Ruby脚本仅负责打印目录名称,然后使用包装shell函数调用该脚本,该函数cd进入Ruby脚本打印出的目录。

如果您希望Ruby脚本与用户交互,请使用STDERR.puts而不是puts

这里有一个示例Ruby脚本cd.rb,它将尝试从用户输入中查找匹配的目录:

#!/usr/bin/env ruby

pattern = ARGV.join(" ")
dirs = Dir.glob("*").filter{|path| File.directory?(path)}.filter{|path| path.include?(pattern)}

if dirs.length == 0
  STDERR.puts "Error: no matching directories found."
  print "."
  exit 1
elsif dirs.length == 1
  print dirs.first
else
  while true do
    STDERR.puts "Which one?"
    dirs.each_with_index{|dir, i|
      STDERR.puts "#{i+1}. #{dir}"
    }
    STDERR.print "=> "
    i = STDIN.gets.chomp.to_i - 1
    if dirs[i]
      print dirs[i]
      exit
    else
      STDERR.puts "Error: uhh what? Try that again...\n\n"
    end
  end
end

这里是包装shzsh脚本,可以将其放入您的.bashrc.zshrc中,并将参数传递给cd.rb,然后cd进入Ruby脚本打印出的目录:

function ,cd () {
  cd "`cd.rb $@`"
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接