使用括号从Ruby运行Bash:'('附近的意外标记

时间:2015-02-05 04:25:17

标签: ruby git bash

我正在尝试编写一个执行一些简单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)获得相同的结果?

1 个答案:

答案 0 :(得分:2)

!(app)是一个bash扩展的glob。所以有两个问题:

  1. ruby使用sh执行系统命令,而不是bash。 (您可以在错误消息中看到,声称来自sh:。)但是,由于您的shbash实施,因此您确实有bash可用,但有一个小问题:当bash作为sh运行时,它会禁用大量特定于bash的功能。

  2. 即使它是bash,也很可能shopt -s extglob尚未执行,这对于!(app)和其他扩展的整体来说是必要的。默认情况下不会启用扩展的globs,但是某些发行版(例如ubuntu)会启用它们以实现选项卡完成,因此您可能已在交互式shell中启用它们。但是,由于ruby没有调用交互式shell,因此很可能没有执行带有shopt -s extglob命令的bash启动文件。

  3. 这一切都无法通过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}是一个元字符。)

    这似乎有效:

    (