将一个字符串转换为 shell 参数

6

我想了解如何将bash输入解析为参数。

例如,在NodeJS中使用process.argv,我们可以获得一个字符串数组(但这与语言无关)。

我的问题是,如何将类似"node foo.js --foo "bar baz" -b foo"的输入解析为类似于process.argv(或其他语言中的等效项)返回的数组(例如["node", "foo.js", "--foo", "\"bar baz\"", "-b", "foo"])?

由于存在引号,仅按空格拆分是不够的。是否可以使用更复杂的正则表达式来处理引号并获取这样的数组?


你需要编写一个模拟 shell 语法的解析器。你试图解决什么问题? - Pointy
@Pointy 实际上,那个 解析器 很可能是一个正则表达式来处理引号。我正在开发一个命令行参数解析器,它几乎完成了,并且接受像 process.argv 这样的数组。但我想做的是让它内部接受字符串(像这个例子中的 bash 命令)并将它们转换为数组。 - Ionică Bizău
我非常怀疑。Shell解析器必须处理不同类型的引号、变量扩展、文件重定向等问题。 - Pointy
@Pointy,我真的不需要文件重定向或其他类似的东西(假设它们已经被bash本身处理了)。我所需要的是一个简单的转换器,将用户提供给我的库的命令转换为一个数组,通过一种bash所做的方式来转义引号。 - Ionică Bizău
Bash不会“转义”引号,它解析命令。因此,你需要一个shell解析器来完成同样的任务。你的解析器可能比shell更简单,因为你不需要处理一些shell所需的功能,但你需要知道哪些是这些功能(以及你支持的shell子集是什么)。 - Etan Reisner
2个回答

5

由于明确要求使用正则表达式解决此问题,尽管这是适合使用正确解析器的任务,但这里提供了一个令人兴奋的正则表达式一行代码。

考虑到以下规范:

  • JS 兼容
  • 按空格分词,但保持 "..."'...' 在一起

可以使用简单的 match 函数查找值,缺点是无法很好地检测引号的嵌套转义(使用正则表达式进行递归匹配非常困难)。

>>> str = "node foo.js --foo \"bar baz\" -b foo";
    str.match(/"[^"]+"|'[^']+'|\S+/g)
<<< ["node", "foo.js", "--foo", "\"bar baz\"", "-b", "foo"]

正则表达式解释:

  • "[^"]+"|'[^']+' 是一个子模式,它查找带有双引号或单引号的内容,中间不包含引号本身。
  • | 表示选项分支。
  • \S\s 的取反:匹配非空白字符序列,这有效地断言我们匹配未被先前收集的符号。量词 + 应用于整个字符串。

两个答案都不错,但是就像我说的,我需要一个小问题的微小解决方案。您能否提及一些这种方法无法正常工作的情况? - Ionică Bizău
@IonicăBizău 当令牌中存在转义引号时,可能会出现问题,例如:""foo \"qux quux\" bar""。除此之外,一切都应该正常工作,包括两种引号的交叉使用:""foo 'bar' baz""。 - Unihedron
很好,很好,很棒!正是我所需要的! - Ionică Bizău

5
使用shell-quote NPM包可以处理这个问题。
var parse = require('shell-quote').parse;
parse('node foo.js --foo "bar baz" -b foo');

[ 'node', 'foo.js', '--foo', 'bar baz', '-b', 'foo' ]

1
这是一个不错的库。然而,对于简单情况(空格和引号以及单引号),我仍在寻找纯正则表达式解决方案。 - Ionică Bizău

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接