我承认以前这里也问过类似的问题,但我见过的所有问题都比我想要实现的要简单。最好只使用 Bash 的解决方案。
我有一个变量,其中包含一个看起来像某种比较的字符串,我想将其拆分为一个数组。以下是一些示例,包括我希望如何拆分它们:
var='name="value"' # arr=([0]=name [1]='=' [2]=value)
var="name != '!value='" # arr=([0]=name [1]='!=' [2]='!value=')
var='"na=me" = value' # arr=([0]=na=me [1]='=' [2]=value)
var='name >= value' # arr=([0]=name [1]='>=' [2]=value)
var='name' # arr=([0]=name)
var='name = "escaped \"quotes\""' # arr=([0]=name [1]='=' [2]=escaped\ \"quotes\")
var="name = \"nested 'quotes'\"" # arr=([0]=name [1]='=' [2]=nested\ \'quotes\')
var="name = 'nested \"quotes\"'" # arr=([0]=name [1]='=' [2]=nested\ \"quotes\")
您明白了吧。两边(或两边都不用)都可以用单引号或双引号引起来。可能会有转义引号或嵌套引号。它们之间的运算符可以是预定义的任何集合,但它们也可以包含在带引号的字符串中。可能有空格,也可能没有空格。可能根本没有运算符。
我必须解析很多行,因此我不想每次都派生出一个新进程,这就是为什么我更喜欢只使用 Bash 的解决方案。这是对现有 Bash 脚本的补充,不需要移植到其他 shell,并且它在 Bash 5.2 上运行,所以我可以使用可能有用的现代 Bash 功能。
IFS=\" read -a arr <<<"$var"
很好,因为它知道如何处理转义引号,如果我只需要处理单引号或双引号而不是两者,我就可以让它工作。就目前而言,我只是希望我不必在 shell 脚本中编写整个标记器算法,并且有一些我尚未考虑过的功能组合可以可靠地解析它。
您需要编写一个解析器:根据当前字符逐个字符地读取字符串,扩展当前单词或开始一个新单词。保留一个标志以指示解析器位于引号字符串内。
像这样:
它正确地解析了您给出的所有示例,但还远未完成(它不检查未关闭的引号等)。
正如 @choroba 指出的那样,您可能无法避免编写词法分析器来拆分输入字符串。幸运的是,使用 ERE 逐个标记“扫描”它们就足够了。我想说使用具有“非捕获”和“命名”组的语言是最好的选择,但如果您坚持使用 Bash,那么您可以这样做:
注意:需要 bash 4.3+
输出:
供读者修复:
我对“变量名”和“运算符”做了一些假设。基本上,“变量名”由字母数字/下划线字符组成;而“运算符”是不包含空格的任何内容(单词和带引号的字符串除外)。
虽然正则表达式使用双引号字符串中存在的任何反斜杠转义序列,但仅
\"
被解释;您可能还需要实现其他转义序列的解码。