【问题标题】:Substituting variables in a text string替换文本字符串中的变量
【发布时间】:2014-10-29 18:01:54
【问题描述】:

我在 bash 的变量中有一个文本字符串,如下所示:

filename1.txt
filename2.txt

varname1 = v1value
$(varname1)/filename3.txt
$(varname1)/filename4.txt

varname2 = $(varname1)/v2value
$(varname2)/filename5.txt
$(varname2)/filename6.txt

我想替换所有变量,产生这个:

filename1.txt
filename2.txt

v1value/filename3.txt
v1value/filename4.txt

v1value/v2value/filename5.txt
v1value/v2value/filename6.txt

任何人都可以建议一种在 shell 中执行此操作的干净方法吗?

【问题讨论】:

  • 这个文件有多大?这种问题实际上用一个好的文本编辑器手动解决起来更快,除非文件真的很大
  • 这只是一个示例。实际上有数百个这样的文件,每个文件中有 0 到 20 个替换。

标签: bash shell macros variable-substitution


【解决方案1】:

我使用m4找到了一个合理的解决方案:

function make_substitutions() {
    # first all $(varname)s are replaced with ____varname____
    # then each assignment statement is replaced with an m4 define macro
    # finally this text is then passed through m4

    echo "$1" |\
    sed 's/\$(\([[:alnum:]][[:alnum:]]*\))/____\1____/' | \
    sed 's/ *\([[:alnum:]][[:alnum:]]*\) *= *\(..*\)/define(____\1____, \2)/' | \
    m4
}

【讨论】:

  • 您可以将这种模式与任何允许这种运行时评估的语言或模板/宏系统一起使用。您甚至可以通过一些努力(和消毒)来使用外壳本身。一个(可能是单程)awk 解决方案也应该相当简单。
【解决方案2】:

也许

echo "$string" | perl -nlE 'm/(\w+)\s*=\s*(.*)(?{$h{$1}=$2})/&&next;while(m/\$\((\w+)\)/){$x=$1;s/\$\($x\)/$h{$x}/e};say$_'

打印

filename1.txt
filename2.txt

v1value/filename3.txt
v1value/filename4.txt

v1value/v2value/filename5.txt
v1value/v2value/filename6.txt

【讨论】:

    【解决方案3】:

    在 awk 中:

    BEGIN {
        FS = "[[:space:]]*=[[:space:]]*"
    }
    
    NF > 1 {
        map[$1] = $2
        next;
    }
    
    function replace(     count)
    {
        for (key in map) {
            count += gsub("\\$\\("key"\\)", map[key])
        }
    
        return count
    }
    
    {
        while (replace() > 0) {}
        print
    }
    

    在 lua 中:

    local map = {}
    
    --for line in io.lines("file.in") do -- To read from a file.
    for line in io.stdin:lines() do -- To read from standard input.
        local key, value = line:match("^(%w*)%s*=%s*(.*)$")
        if key then
            map[key] = value
        else
            local count
            while count ~= 0 do
                line, count = line:gsub("%$%(([^)]*)%)", map)
            end
            print(line)
        end
    end
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-04
      • 1970-01-01
      • 2013-02-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多