我正在尝试编写一个执行一些简单git命令的Ruby脚本。我想列出不在我的app目录中的所有文件更改。
运行以下内容以获取终端中的所有更改:
git ls-files -m
收率:
config/environment.rb
app/models/site.rb
在终端中使用通配符异常运行:
git ls-files -m !(app)
收率:
config/environment.rb
使用以下方法在Ruby中执行相同操作:
`git ls-files -m !(app)`
收率:
sh: -c: line 0: syntax error near unexpected token `('
sh: -c: line 0: `git ls-files -m !(app)'
我试图添加双重逃脱:
`git ls-files -m \\!\\(app\\)`
没有错误但是结果为空。
我也尝试过使用Shellwords:
require 'shellwords'
`git ls-files -m #{Shellwords.escape("!(app)")}`
没有错误但是结果为空。
使用%x[]
语法的行为与反引号完全相同,但似乎并不像我喜欢的那样。
如何在Ruby中运行git ls-files -m !(app)
获得相同的结果?
答案 0 :(得分:2)
!(app)
是一个bash扩展的glob。所以有两个问题:
ruby
使用sh
执行系统命令,而不是bash
。 (您可以在错误消息中看到,声称来自sh:
。)但是,由于您的sh
由bash
实施,因此您确实有bash可用,但有一个小问题:当bash
作为sh
运行时,它会禁用大量特定于bash的功能。
即使它是bash
,也很可能shopt -s extglob
尚未执行,这对于!(app)
和其他扩展的整体来说是必要的。默认情况下不会启用扩展的globs,但是某些发行版(例如ubuntu)会启用它们以实现选项卡完成,因此您可能已在交互式shell中启用它们。但是,由于ruby没有调用交互式shell,因此很可能没有执行带有shopt -s extglob
命令的bash启动文件。
这一切都无法通过ruby使用命令,但它确实使生活变得复杂。例如,一种可能的解决方法是启用BASHOPTS并强制bash
运行:
`env BASHOPTS=$BASHOPTS:extglob bash -c 'git ls-files -m !(app)'`
可能比使用grep -v
过滤掉不需要的目录名称的替代解决方案更复杂。
使用BASHOPTS
设置env
实际上只有/bin/sh
真的bash
才有效,所以直接shopt
可能会更好执行的命令。这是直截了当的,但有一个小皱纹;你需要在shopt
命令和扩展glob的使用之间引入一个换行符,因为bash tokenizes一次命令一行(并且如果extglob
在标记时没有设置,{{1}是一个元字符。)
这似乎有效:
(