【问题标题】:Command-line: Insert the output from a unix command at a given point in a template file命令行:在模板文件的给定点插入 unix 命令的输出
【发布时间】:2014-06-30 00:48:00
【问题描述】:

我一直在寻找一种单行方法,将模板文件中的匹配字符串替换为文件的 base64 字符串。所以在下面的模板文件中:

# config.template.yaml

is_real: "yes"
project_base64: {base64_string}
file_name: "project.tgz"

在一行中将{base64_string} 替换为base64 -w0 project.tgz 的输出。

我尝试使用 sed 如下:

sed s/{base64_string}/`base64 -w0 project.tgz`/ config.template.yaml > config.yaml

如果project.tgz 很小,这可以正常工作,但由于它实际上是几兆字节,我收到一个错误:

bash: /bin/sed: Argument list too long

【问题讨论】:

    标签: templates unix command-line awk sed


    【解决方案1】:

    我最终采用的解决方案是使用awk,由于没有人理解awk,我想我会把它贴在这里以防其他人有类似的问题:

    awk '{"base64 -w0 project.tgz"|getline b64; gsub("{base64_string}", b64); print}' config.template.yaml > config.yaml
    

    说明

    awk 是一个极其复杂的命令行工具,它针对文件的每一行运行一个小程序。程序用大括号括起来:awk '{<your program here>}' <filename>

    我很快意识到gsub 函数是我的解决方案。花费我最多时间的部分是研究如何将 bash 命令的输出传递给gsub。原来getline 是我的解决方案。如果你执行"<some bash command>"|getline <var_name>,它会将命令输出的第一行存储在该变量名中。

    那么上面一行对config.template.yaml的每一行做了什么:

    • base64 -w0 project.tgz的输出保存在变量b64
    • 在线运行gsub({base64_string}, b64),用base64 -w0 project.tgz的输出替换所有出现的{base64_string}
    • 将输出打印到 STDOUT

    然后我将所有输出重定向到一个新文件config.yaml,瞧!

    【讨论】:

    • "既然没人理解awk..."?真的吗?是什么让你得出这个结论?我怀疑有足够的相反证据......
    • awk 再简单不过了。你不明白,成千上万的人明白。上面发布的“解决方案”非常复杂且容易出错。
    • @Robin,您当然不想为模板中的每一行计算 base64 值。请仔细阅读 Ed Morton 的回答。
    【解决方案2】:
    $ cat file
    is_real: "yes"
    project_base64: {base64_string}
    file_name: "project.tgz"
    
    $ awk -v b64="$(printf "hello\nworld\n")" '{gsub(/{base64_string}/, b64); print}' file
    is_real: "yes"
    project_base64: hello
    world
    file_name: "project.tgz"
    

    printf "hello\nworld\n" 替换为base64 -w0 project.tgz

    【讨论】:

    • b64的内容长时,得到bash: /usr/bin/awk: Argument list too long
    【解决方案3】:

    当命令使用<(command)(在您的情况下为<(base64 -w0 project.tgz))伪装成文件时,您可以使用 awk 将命令的输出存储在数组中。
    接下来可以在处理file2时写入数组。

    awk 'NR==FNR {a[NR]=$0;next}
        /^project_base64:/ { printf "project_base64:";
                             for (i=1; i <= length(a); i++) { print a[i] };
                             next
                           }
        {print}' <(base64 -w0 project.tgz) config.template.yaml
    

    当要插入的命令只有一行时,插入数组不需要循环。选项-w0 允许进行下一个简化:

    awk 'NR==FNR {a[NR]=$0; next}
        /^project_base64:/ { print "project_base64:" a[1];
                             next
                           }
        {print}' <(base64 -w0 project.tgz) config.template.yaml
    

    当你想使用sed时,确保base64sed执行:

    sed 's/{base64_string}/printf "%s" "&";base64 -w0 project.tgz/e' config.template.yaml 
    

    【讨论】:

    • 不需要 for 循环.. 只需打印 a[1] awk 'NR==FNR {a[NR]=$0;next} /^project_base64:/ { printf "project_base64:"; print a[1] ;next } {print}' &lt;(base64 -w0 project.tgz) config.template.yaml 为我工作
    • @stack0114106 你说得对,我没有看选项-w0抑制换行。
    【解决方案4】:

    使用 Perl,

    $ cat config.template.yaml
    is_real: "yes"
    project_base64: {base64_string}
    file_name: "project.tgz"
    
    $  perl -pe ' s/\{base64_string\}/qx(base64 -w0 project.tgz)/ge if /project_base64/ ' config.template.yaml
    is_real: "yes"
    project_base64: MTIzCg==
    file_name: "project.tgz"
    

    【讨论】:

      猜你喜欢
      • 2021-12-23
      • 2016-03-16
      • 2013-03-06
      • 1970-01-01
      • 2014-05-15
      • 1970-01-01
      • 2012-02-18
      • 2015-06-26
      • 1970-01-01
      相关资源
      最近更新 更多