在Ruby脚本中坚持环境更改

在Ruby脚本中坚持环境更改,ruby,scripting,Ruby,Scripting,这是我的剧本 #!/usr/bin/env ruby if __FILE__ == $0 `cd ..` puts `ls` end 它运行良好,但当它退出时,我回到了我开始的地方。如何“导出”我对环境所做的更改?这是因为backtick操作符不适用于复杂的环境 脚本编写。它对于运行单个命令(和捕获)非常有用 它的输出)。它背后没有外壳来存储环境更改 在调用之间和Ruby脚本终止之后 在Linux系统上,每个进程都有自己的当前目录路径(它 可在/proc/èpid›/cwd

这是我的剧本

#!/usr/bin/env ruby
if __FILE__ == $0
    `cd ..` 
    puts `ls` 
end

它运行良好,但当它退出时,我回到了我开始的地方。如何“导出”我对环境所做的更改?

这是因为backtick操作符不适用于复杂的环境 脚本编写。它对于运行单个命令(和捕获)非常有用
它的输出)。它背后没有外壳来存储环境更改 在调用之间和Ruby脚本终止之后

在Linux系统上,每个进程都有自己的当前目录路径(它 可在
/proc/èpid›/cwd
中找到。在进程中更改目录 不影响父进程(从中运行程序的shell)。如果 内置的
cd
是一个二进制文件,它只能更改自己的当前值 目录,而不是父进程的目录,这就是为什么
cd
命令只能是内置的


替代实现 如果必须从shell执行Ruby脚本并且必须影响 在shell的当前目录路径中,可以使用以下技巧。 不要在Ruby中运行命令,而是将这些命令打印到 标准输出,然后
source
将其发送到正在运行的shell 来自的Ruby脚本。这些命令将不会由单独的 一个shell的进程,因此所有
cd
s将在当前 shell实例

因此,与其

ruby run_commands.rb
在shell脚本中编写如下内容:

source <(ruby prepare_and_print_commands.rb)
在当前目录中工作 工作原理与普通外壳中的
test
函数类似

定义自定义命令和别名 定义的命令的名称可用于以后运行它(确切地说是 与使用预定义的
echo
cat
的方式相同(例如)

使用目录堆栈 这里使用上面定义的自定义
list
命令

顺便说一下,有一个方便的
chdir
命令可以运行多个 命令并返回到上一个工作目录 在那之后

puts sh.pwd
sh.chdir('/tmp') do
    puts sh.pwd
end
puts sh.pwd
跳过一组命令的shell对象 附加功能 此外,
Shell
类具有:

  • 用于迭代文件中的行或通过 目录中的文件列表(取决于给定的路径点 到文件或目录)
  • jobs
    kill
    命令控制进程
  • 一组用于操作文件的命令,例如
    basename
    chmod
    chown
    delete
    dirname
    rename
    stat
    symlink
  • 许多
    文件
    方法的同义词:
    目录?
    可执行文件?
    存在?
    可读?
  • FileTest
    类方法等价的方法:
    syscopy
    copy
    移动
    比较
    安全解除链接
    生成目录
    ,以及
    安装

“它背后没有外壳来存储调用之间的环境变化”。。。有。这就是在两个命令之间保持状态的原因(更新了问题以演示这一点)。但“在您的Ruby脚本终止后”如何保持状态?谢谢。1.8.7,但是达尔文(OSX)。刚刚确认这至少与Ubuntu不同。然而,在Linux上你可以做“系统'cd..”,这是有效的。对不起,在Ubuntu上它返回false。在Mac上返回true。我在答案中添加了对Linux系统上“当前目录”概念的解释(第二段)。因此,至少在Linux上,您不能影响父进程的当前目录(相对于您的脚本)。看起来Ruby中的
系统
调用在Linux和Mac OS X上的实现方式不同。据我所知(我大部分时间都在使用Linux),当前目录是每个进程的,不仅基于Linux,而且基于类似Unix的系统。
puts "Working directory: #{sh.pwd}"
(sh.echo 'test') | (sh.tee 'test') > STDOUT
# Redirecting possible to "left" as well as to "right".
(sh.cat < 'test') > 'triple_test'
# '>>' and '<<' are also supported.
sh.cat('test', 'test') >> 'triple_test'
puts sh.test('e', 'test')
# or
puts sh[:e, 'test']
puts sh[:exists?, 'test']
puts sh[:exists?, 'nonexistent']
#                        name    command line to execute
Shell.def_system_command 'list', 'ls -1'

#                   name   cmd   command's arguments
Shell.alias_command "lsC", "ls", "-CBF"
Shell.alias_command("lsC", "ls") { |*opts| ["-CBF", *opts] }
sh.pushd '/tmp'
sh.list > STDOUT
(sh.echo sh.pwd) > STDOUT
sh.popd
sh.list > STDOUT
(sh.echo sh.pwd) > STDOUT
puts sh.pwd
sh.chdir('/tmp') do
    puts sh.pwd
end
puts sh.pwd
# Code above, rewritten to drop out 'sh.' in front of each command.
sh.transact do
    pushd '/tmp'
    list > STDOUT
    (echo pwd) > STDOUT
    popd
    list > STDOUT
    (echo pwd) > STDOUT
end