0

我遇到了一个从 CLI(不在框架中)调用的 ruby​​ 脚本的问题,在尝试打开它时会导致 ENOENT 错误(文件不存在),但仅在使用 gsub 正则表达式替换构建文件名时. 当字符串由任何其他方法构造时,它可以工作。我敢肯定,我做错了很简单,但是我花了很长时间才弄清楚。

系统信息

# lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 12.04.3 LTS
Release:        12.04
Codename:       precise

# rvm -v
rvm 1.23.13 (stable) by Wayne E. Seguin <wayneeseguin@gmail.com>, Michal Papis <mpapis@gmail.com> [https://rvm.io/]
# ruby -v
ruby 2.0.0p195 (2013-05-14 revision 40734) [x86_64-linux]

Filesystem: ext2

Permissions:
# ls -lah /home/boise/config
total 24K
drwxr-xr-x  2 boise boise 4.0K Nov 13 19:40 .
drwxr-xr-x 11 boise boise 4.0K Nov 13 20:22 ..
-rwxr-xr-x  1 boise boise  248 Nov 13 09:31 boise.yaml
-rwxr-xr-x  1 boise boise  335 Nov 13 19:35 config.rb
-rwxr-xr-x  1 boise boise  339 Nov 13 20:06 stanford.yaml
-rwxr-xr-x  1 boise boise  248 Nov 13 09:49 test.yaml


user being used to run scripts and owns containing directory is 'boise' 
there is nothing abnormal about the file system here, no symbolic links or 
mappings or anything like that.

我启动了一个简单的脚本来重现错误。在此,我将其简化为尽可能简单,将路径的前缀设为静态并使用绝对路径,这样就没有关于相对路径或当前工作目录的问题。

脚本名称:测试

#!/usr/bin/env ruby
require 'yaml'

# Here we are "hardcoding" the values.
$config_yaml = "boise.yaml"
puts $config_yaml
config_filespec = "/home/boise/config/#{$config_yaml}"
puts config_filespec
puts File.exists? config_filespec
$configuration = YAML.load(File.open(config_filespec))

$verbose = true
hosts = []
args = []

puts $config_yaml

ARGV.each do |arg|
  if arg.match /hosts\=(.*?)/i
    hosts = ARGV.delete(arg).gsub(/hosts\=(.*?)/i,'\2').split(',')
  elsif arg == "quiet"
    $verbose = false
    ARGV.delete(arg)
  elsif arg.match /cfg=(.*?)/
    #Here the value of the YAML file to be loaded is set with a regular expression substitution.
    $config_yaml = ARGV.delete(arg).gsub(/cfg=(.*?)/, "\2")
  else
  end
end

#do the same output as we did the first time hardcoded, but this time the
#value got reset by a gsub -- same variable, same name, etc

puts $config_yaml
config_filespec = "/home/boise/config/#{$config_yaml}"
puts config_filespec
puts File.exists? config_filespec
$configuration = YAML.load(File.open(config_filespec))

这可以按预期工作:

# ./testing
boise.yaml
/home/boise/config/boise.yaml
true
boise.yaml
boise.yaml
/home/boise/config/boise.yaml
true

但是请注意当我将 yaml 字符串作为命令行参数传递时会发生什么。请注意,这甚至是完全相同的文件名!

# ./testing cfg=boise.yaml

boise.yaml
/home/boise/config/boise.yaml
true
boise.yaml
boise.yaml
/home/boise/config/boise.yaml
false
./testing:31:in `initialize': No such file or directory - /home/boise/config/boise.yaml (Errno::ENOENT)
        from ./testing:31:in `open'
        from ./testing:31:in `<main>'

我还尝试使用 String(config_filespec)、config_filespec.to_s 强制转换字符串,并使用 + "" 进行字符串连接,希望这是字符串与文字或正则表达式或类似的一些类型问题。有任何想法吗?

提前感谢堆栈溢出!

4

1 回答 1

1

答案是你没有得到你认为你从 gsub 得到的结果。这归结为一个红宝石怪癖。使用双引号时,“\2”的计算结果为“002”。但是,使用单引号 '\2' 将返回第二个捕获组。在您的代码中...

$config_yaml = ARGV.delete(arg).gsub(/cfg=(.*?)/, '\2')

如果您只接受一个文件名,是否值得使用拆分?

$config_yaml = ARGV.delete(arg).split(/=/, 2).last
于 2013-11-14T03:31:32.027 回答