运行 Bash from Ruby with parentheses: unexpected token near '('
Running Bash from Ruby with parentheses: unexpected token near '('
我正在尝试编写一个 Ruby 脚本来执行一些简单的 git 命令。我想列出所有不在我的应用程序目录中的文件更改。
运行 以下获取终端中的所有更改:
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[]
语法的行为也与反引号完全一样,但似乎并不像我希望的那样工作。
关于如何从 运行 git ls-files -m !(app)
在 Ruby 中获得相同结果的任何想法?
!(app)
是一个 bash 扩展 glob。所以有两个问题:
ruby
使用 sh
来执行系统命令,而不是 bash
。 (您可以在声称来自 sh:
的错误消息中看到这一点。)但是,由于您的 sh
是由 bash
实现的,您确实有 bash 可用,有一个小问题:当 bash
被 运行 宁为 sh
时,它会禁用很多 bash 特定的功能。
即使是bash
,也很有可能shopt -s extglob
没有被执行,这是!(app)
和其他扩展globs工作所必需的.默认情况下不启用扩展 glob,但某些发行版(例如 ubuntu)启用它们以实现制表符完成,因此您可能在交互式 shell 中启用了它们。但是,由于 ruby 没有调用交互式 shell,很可能 bash 带有 shopt -s extglob
命令的启动文件没有被执行。
None 使得无法通过 ruby 使用命令,但这确实使生活复杂化。例如,一种可能的解决方法是启用 BASHOPTS 并强制 bash
到 运行:
`env BASHOPTS=$BASHOPTS:extglob bash -c 'git ls-files -m !(app)'`
这可能比使用 grep -v
.
过滤不需要的目录名称的替代解决方案更复杂
使用 env
设置 BASHOPTS
实际上只有在 /bin/sh
确实是 bash
时才有效,所以 shopt
可能会更好直接在执行的命令中。这是直截了当的,但有一点小问题;您需要在 shopt
命令和扩展 glob 的使用之间引入一个换行符,因为 bash 一次标记一行命令(如果在标记化时未设置 extglob
,则(
是元字符。)
这似乎有效:
`bash -c "shopt -s extglob\ngit ls-files -m !(app)"`
我正在尝试编写一个 Ruby 脚本来执行一些简单的 git 命令。我想列出所有不在我的应用程序目录中的文件更改。
运行 以下获取终端中的所有更改:
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[]
语法的行为也与反引号完全一样,但似乎并不像我希望的那样工作。
关于如何从 运行 git ls-files -m !(app)
在 Ruby 中获得相同结果的任何想法?
!(app)
是一个 bash 扩展 glob。所以有两个问题:
ruby
使用sh
来执行系统命令,而不是bash
。 (您可以在声称来自sh:
的错误消息中看到这一点。)但是,由于您的sh
是由bash
实现的,您确实有 bash 可用,有一个小问题:当bash
被 运行 宁为sh
时,它会禁用很多 bash 特定的功能。即使是
bash
,也很有可能shopt -s extglob
没有被执行,这是!(app)
和其他扩展globs工作所必需的.默认情况下不启用扩展 glob,但某些发行版(例如 ubuntu)启用它们以实现制表符完成,因此您可能在交互式 shell 中启用了它们。但是,由于 ruby 没有调用交互式 shell,很可能 bash 带有shopt -s extglob
命令的启动文件没有被执行。
None 使得无法通过 ruby 使用命令,但这确实使生活复杂化。例如,一种可能的解决方法是启用 BASHOPTS 并强制 bash
到 运行:
`env BASHOPTS=$BASHOPTS:extglob bash -c 'git ls-files -m !(app)'`
这可能比使用 grep -v
.
使用 env
设置 BASHOPTS
实际上只有在 /bin/sh
确实是 bash
时才有效,所以 shopt
可能会更好直接在执行的命令中。这是直截了当的,但有一点小问题;您需要在 shopt
命令和扩展 glob 的使用之间引入一个换行符,因为 bash 一次标记一行命令(如果在标记化时未设置 extglob
,则(
是元字符。)
这似乎有效:
`bash -c "shopt -s extglob\ngit ls-files -m !(app)"`