是否可以获取用于调用ruby脚本的未解释的命令行?

时间:2014-02-27 00:30:49

标签: ruby command-line

根据标题,是否可以获取用于调用ruby脚本的原始命令行?

我直接调用命令后,我所遵循的确切行为类似于SSH:

ssh somehost -- ls -l

SSH将在服务器上运行“ls -l”。它需要被解析,因为如果shell已经解释了引号并执行了扩展等,那么命令可能无法正常工作(如果它包含引号等)。这就是ARGV不好的原因;报价被剥夺了。

考虑以下示例:

my-command -- sed -e"s/something/something else/g"

ARGV包含以下内容:

--
sed
-es/something/something else/g

sed命令将失败,因为引号将被剥离,替换命令中的空格意味着sed将不会看到“else / g”。

那么,要重新迭代,是否可以获取用于调用ruby脚本的原始命令行?

3 个答案:

答案 0 :(得分:3)

不,这是在操作系统级别。

您可以尝试简单地引用整个输入:

my-command -- "sed -e\"s/something/something else/g\""

在Ruby中,可以这样使用:

ruby -e "puts ARGV[0]" -- "sed -e\"s/something/something else/g\""
(output) sed -e"s/something/something else/g"

或者,在文件putsargv1.rb中(内容为puts ARGV[1]):

ruby -- "putsargv1.rb" "sed -e\"s/something/something else/g\""
(output) sed -e"s/something/something else/g"

答案 1 :(得分:1)

你的例子被误导了。 ssh somehost -- ls *将在localhost上扩展*(例如ls localfile1 localfile2 localfile3),然后在远程主机上执行该操作,结果导致很多ls: cannot access xxx: No such file or directory错误。 ssh没有看到未解释的命令行。

正如您所说,您将获得-es/something/something else/g作为单个参数。这正是sed所能获得的。实际上,这与您撰写-e"s/something/something else/g""-es/something/something else/g"以及-es/something/something\ else时所获得的内容相同。

使用此事实,您可以使用Shellwords.shellescape“保护”空格和其他不可用的内容,然后再将其移交给外部进程。您无法获得原始行,但您可以确保保留语义。

答案 2 :(得分:0)

Shellescape在args上工作但是并没有完全模仿SSH。采用以下示例(请参阅下面的test.rb内容):

ruby test.rb -- ls -l / \| sed -e's/root/a b c/g'

这将使用shellescape方法失败,但使用SSH成功​​。我选择手动转义引号和空格。可能会有一些边缘情况无法捕获,但它似乎适用于大多数情况。

require 'shellwords'

unparsed = if ARGV.index('--')
  ARGV.slice(ARGV.index('--') + 1, ARGV.length)
end || []

puts "Unparsed args: #{unparsed}"

exit if unparsed.empty?

shellescaped = unparsed.map(&Shellwords.method(:shellescape)).join(" ")
quoted = unparsed.map do |arg|
  arg.gsub(/(["' ])/) { '\\' + $1 } 
end.join(" ")

puts "Shellescaped: #{shellescaped}"
puts `bash -c #{shellescaped.shellescape}`

puts "Quoted: #{quoted}"
puts `bash -c #{quoted.shellescape}`

感谢您的回答:)