如何用sed替换双引号字符串中的所有变量之前的所有美元符号?

时间:2019-02-24 14:17:06

标签: regex string bash sed

我在替换bash字符串中的变量时遇到问题。例如,我要替换

        $resulting = $query->result_array(); 
        $currentDateTime = date('Y-m-d H:i:s');
        foreach($resulting as $resultings){ 
            $date = $resultings['eventDate']; 
            $this->db->where('activityId', $resultings['activityId']);
            if (strtotime($currentDateTime) == strtotime($date)) { 
                 $this->db->update('activity', array('eventStatus' => 1));
            } else if (strtotime($currentDateTime) < strtotime($date)) { 
                 $this->db->update('activity', array('eventStatus' => 3));
            } else if (strtotime($currentDateTime) > strtotime($date)) { 
                 $this->db->update('activity', array('eventStatus' => 1));
            } 
        }

具有:

"test$FOO1=$FOO2" $BAR

我尝试过:

"test" .. FOO1 .. "=" .. FOO2 .. "" $BAR

但是我不想用双引号之外的字符串来替换变量,例如喜欢:

sed 's/\$\([A-Z0-9_]\+\)\b/" .. \1 .. "/g'

只需替换为

if [ $VARIABLE = 1 ]; then

是否可以仅替换内部双引号?

背景:
我要convert a bash script into Lua script

我知道,以这种方式转换所有可能的shell脚本不是一件容易的事,但是我要实现的是用Lua命令替换所有基本语言结构,并替换所有变量和条件。将bash手动翻译成Lua时,这里的自动化将节省大量工作

4 个答案:

答案 0 :(得分:0)

这与用于多字​​符RS,RT和gensub()的GNU awk一起,展示了一种分离并随后处理带引号(在RT中)和无引号(在$ 0中)字符串作为起点的方法:

$ cat tst.awk
BEGIN { RS="\"[^\"]*\""; ORS="" }
{
    $0 = gensub(/\[\s+[$]([[:alnum:]_]+)\s+=\s+\S+\s+];/,"\\1","g",$0)
    RT = gensub(/[$]([[:alnum:]_]+)"/,"\" .. \\1","g",RT)
    RT = gensub(/[$]([[:alnum:]_]+)/,"\" .. \\1 .. \"","g",RT)
    print $0 RT
}

$ awk -f tst.awk file
"count: " .. FOO .. " times " .. BAR
if VARIABLE then

以上操作是在此输入文件上执行的:

$ cat file
"count: $FOO times $BAR"
if [ $VARIABLE = 1 ]; then

注意:根据提供的示例,这种将字符串与正则表达式匹配的方法永远只是尽力而为,您需要一个shell语言解析器来稳健地完成这项工作。

答案 1 :(得分:0)

这可能对您有用(GNU sed):

sed -E ':a;s/^([^"]*("[^"$]*"[^"]*)*"[^"$]*)\$([^" ]*) /\1" .. \3  .. " /;ta;s/^([^"]*("[^"$]*"[^"]*)*"[^"$]*)\$([^"]*)"/\1" .. \3/;ta' file

在双引号中更改内容时,首先,我们必须通过任何不需要需要更改的双引号字符串。这意味着使用^元字符将正则表达式锚定到行的开头,并迭代正则表达式直到所有情况都不再存在。

首先,请从行首开始消除零个或多个不是双引号的字符。

第二,消除不包含感兴趣字符(TCOI)的双引号字符串,即$,后跟零个或多个不是双引号的字符,零次或多次。

第三,消除双引号,后跟零个或多个不是双引号或TCOI的字符,即$

以下字符(如果存在)必须为TCOI。在反向引用\1之前将整个字符串集合分组。

在TCOI之后,可以对一个或多个条件进行分组。在上面的示例中,第一个条件是变量(以TCOI开头)后跟空格。第二个条件是变量直接跟在"之后。因此,这需要两个替换命令ta命令,当替换成功时,它们会分支到标识为a的循环。

if [ $VARIABLE = 1 ]; then的情况可以用同样的方式处理,这里的[是开始的双引号,]是结束的双引号。

P.S。 TCOI为$,它也是regexp中的一个元字符,代表一行的结尾,因此必须用例如\$

引起来。

P.P.S。不要忘记引用[]。如果引用不是您的事,则将字符括在[x]中,其中x是要引用的字符。

编辑:

sed -E ':a;s/^([^"]*("[^"$]*"[^"]*)*"[^"$]*)\$([[:alnum:]]*)/\1" .. \3  .. "/;ta' file

由于原始示例已被OP取代,因此以下是基于新示例的解决方案。

答案 2 :(得分:0)

bash lexer for shell!?

很抱歉:我只是发布此答案以警告您错误的方法!

阅读语言是一致的 lexer 的工作,而不是 sed 或任何基于 regex 的工具! !

请参见GNU BisonBerkeley Yacc (byacc)

您可以查看的来源,以了解如何阅读脚本!

以这种方式坚持下去将使您快速进入大型脚本,然后进一步解决无法解决的问题。

答案 3 :(得分:0)

使用组和递归

sed -e ':a' -e 's/^\(\([^"]*\("[^"]*"\)*\)*\)\("[^$"]*\)[$]\([A-Z0-9_]\{1,\}\)/\1\4 .. \5 .. /;t a'
  1. 用上一部分隔离字符串 第1组中的^\(\([^"]*\("[^"]*"\)*\)*\)
  2. 在第4组(前缀)和第5组(变量名)中用s\("[^$"]*\)[$]\([A-Z0-9_]\{1,\}\)'分隔的字符串中选择var内容
  3. 使用\1\4 .. \5 ..随心所欲地更改
  4. :at a发生更改时重复此操作

使用gnu sed可以将命令减少为(无需使用-e来定位标签a):

sed ':a;s/^\(\([^"]*\("[^"]*"\)*\)*\)\("[^$"]*\)[$]\([A-Z0-9_]\{1,\}\)/\1\4 .. \5 .. /;t a'

假定字符串中没有引号(转义的一个)。如果是这样,则需要先通过更改它们,然后在进行主要修改后放回它们。