代码之家  ›  专栏  ›  技术社区  ›  leifg

将命令行参数解析为通配符

  •  2
  • leifg  · 技术社区  · 15 年前

    我编写了一个简单的脚本,将所有给定的参数写入一个单独的文本文件,用换行符分隔。我想使用OptionParser将文件列表传递给它。我想添加一些使用通配符的文件,如 /dir/* .

    我试过这个:

    opts = OptionParser.new 
    opts.on('-a', '--add FILE') do |s| 
      puts "DEBUG: before #{s}"
      @options.add = s
      puts "DEBUG: after #{@options.add}"
    end
    ...
    def process_arguments
      @lines_to_add = Dir.glob @options.add
    end
    

    添加此类文件时放置:

    ./script.rb -a /path/*
    

    我总是只得到目录中的第一个文件。所有的调试输出都只显示目录的第一个文件,并且似乎OptionParser做了一些神奇的解释。

    有人知道怎么处理这个吗?

    4 回复  |  直到 10 年前
        1
  •  4
  •   Greg Hewgill    15 年前

    您没有提到正在使用的操作系统(这很重要)。

    在Windows上,无论您在命令行上键入什么,都会在不进行修改的情况下传递给程序。所以如果你打字

    ./script.rb -a /path/*
    

    然后程序的参数包含 "-a" "/path/*" .

    在具有类似shell的Unix和其他系统上,shell 参数展开 它会自动扩展命令行中的通配符。因此,当您在上面键入相同的命令时, 查找中的文件 /path/* 并在程序运行之前展开命令行参数。所以程序的参数可能是 “-A” , "/path/file1" "/path/file2" .

    重要的一点是,脚本无法确定参数扩展是否发生,或者用户是否在命令行上实际键入了所有这些文件名。

        2
  •  3
  •   the Tin Man    10 年前

    如上所述,在操作系统将命令交给Ruby之前,正在解析命令行。正在将通配符扩展为以空格分隔的文件名列表。

    如果你输入类似 echo * 然后在命令行,而不是点击 返回 相反,击中 ESC 然后 * . 你应该看到 * 扩展到匹配文件列表中。

    击球后 返回 这些名称将添加到argv数组中。OptionParser将遍历argv并找到您定义的标志,必要时获取以下元素,然后将它们从argv中移除。完成OptionParser后,任何不适合选项的argv元素都将保留在argv数组中,您可以从中获取它们。

    在代码中,您正在为 '-a' '--add FILE' 选择权。OptionParser具有 Array 选项,它将从命令行中获取逗号分隔的元素,但随后将获取空格分隔的元素。

    require 'optparse'
    
    options = []
    opts = OptionParser.new 
    opts.on('-a', '--add FILE', Array) do |s| 
      options << s
    end.parse!
    
    print "options => ", options.join(', '), "\n"
    print "ARGV => ",    ARGV.join(', '),    "\n"
    

    将其保存到一个文件中,并尝试使用命令行 -a one two three 然后 -a one,two,three . 你会看到 数组 选项根据参数之间是否有逗号或空格来不同地获取元素。

    因为 * 通配符被空格分隔的文件名替换,在OptionParser对其运行之后,您必须发布进程argv,或者以编程方式全局化目录并以这种方式构建列表。argv拥有除在 -a 所以,就个人而言,我会放弃 -A 选项并让argv包含所有文件。

    如果 * 文件太多,超过了缓冲区大小。你会知道这是否发生,因为操作系统会抱怨。

        3
  •  0
  •   Ignacio Vazquez-Abrams    15 年前

    在将参数传递给程序之前,shell正在扩展该参数。要么继续使用文件名,直到找到另一个选项,要么让用户退出通配符(例如 ./script.rb -a '/path/*' )你自己去把它们全球化。

        4
  •  0
  •   the Tin Man    10 年前

    现在所发生的是shell在Ruby到达通配符之前对它进行了扩展。所以你真的在处理:

    ./script.rb -a /path/file1 /path/file2 ......
    

    加引号 /path/* 要避免shell扩展并将通配符传递给ruby:

    ./script.rb -a '/path/*'
    
    推荐文章