当我捕获文件时获取变量

时间:2011-05-17 01:33:12

标签: bash shell variables sh cat

是否有可能以一种干净的方式在我捕获文件时获取变量值,而不是在文件中写入的变量名。这很难解释,但这里有一个简单的例子:

$ cat <<EOF
$HOME
EOF
/home/myself

cat返回/ home /我,因为它已经被shell扩展了。

$ echo \$HOME >/tmp/home
$ cat /tmp/home
$HOME

cat只是读取文件,我想通过cat以某种方式将$ HOME扩展到此处,因为该文件将包含变量名称(不像HOME = / home / myself)

我的问题是,这是否可能以某种方式,否则我将不得不写一些脏代码。

编辑:它们是包含

的大型xml文件
<checkbox active="$value">

是或否

4 个答案:

答案 0 :(得分:2)

在Python中尝试这是微不足道的,看看它是否适合你。您可以使用re.sub函数通过调用执行转换的函数(而不是替换它的特定字符串)来替换某些模式(例如"\$\w+")的所有实例。对于替换函数,您可以使用os.getenv(),它当然采用变量名称并返回其值。

编辑:这是一个完整的Python脚本,可以执行上述操作:

#!/usr/bin/python

import fileinput
import os
import re

def transform(match):
    return os.getenv(match.group(1)) # replace the "capture" to omit $

for line in fileinput.input(): # reads from stdin or from a file in argv
    print re.sub('\$(\w+)', transform, line), # comma to omit newline

答案 1 :(得分:1)

cat将其输入不变地复制到其输出 - 至少在其原始(第1版UNIX)表单中。它没有任何选择。然后BSD增加了一堆,最初的UNIX团队反对:'cat从伯克利挥手挥舞旗帜回来了(参见:1 - passim)。它不应该用于编辑文件 - 这不是它的目的。 (我找到了对cat的BSD(Mac OS X)手册页中的文章的引用:Rob Pike,“UNIX Style,或者cat -v Considered Harmful”,USENIX夏季会议诉讼程序,1983年。另见http://quotes.cat-v.org/programming/

因此,您需要cat以外的其他工作来完成这项工作。我推荐Perl或Python;要么可以很容易地做到这一点。或者,请考虑sed,或者awk

#!/usr/bin/env perl
use strict;
use warnings;
while (<>)
{
    foreach my $key (keys %ENV)
    {
        s/\$$key\b/$ENV{$key}/g;  # $envvar
        s/\${$key}/$ENV{$key}/g;  # ${envvar}
    }
    print;
}

循环输入行,依次查找每个环境变量。替代机制是寻找可能的变量并进行相关替换。事实证明这有点棘手,但可行:

#!/usr/bin/env perl
use strict;
use warnings;
while (<>)
{
    while (m/\$((\w+))/ || m/\$({(\w+)})/)
    {
        my $key = $2;
        my $var = $1;
        s/\$$var/$ENV{$key}/g if defined $ENV{$key};
    }
    print;
}

当我在捕获中包含文字$时,替换操作无效。

答案 2 :(得分:1)

显而易见的方法有很多问题:

# This will fail with certain inputs.  HTML will certainly be a problem
# as the '<' and '>' characters will be interpreted as file redirects
$ while read r; do eval echo $r; done < input

以下perl应该能够很好地处理简单输入的问题。

$ perl -pwe 'while(($k,$v) = each %ENV ) { s/\${?$k}?/$v/ }' input

但它对$ {FOO-bar}这样的结构没有任何作用。如果你需要处理这样的结构,可能就足以转义所有的shell元字符并执行while / read循环:

$ sed -e 's/\([<>&|();]\)/\\\1/g' input | while read -r l; do eval echo "$l"; done

请注意,这既不健壮也不安全。考虑在输入上发生的事情,如:

\; rm -rf /

我说“考虑”。不要测试。 sed将在分号前插入反斜杠,然后eval将获得字符串“\\;”这将被解释为单个反斜杠后跟一个分号终止回声,并且将执行rm -rf。鉴于评估未知输入的不安全性,坚持像perl这样的东西并明确地替换所需的sh构造可能更安全。类似的东西:

$ perl -pwe 'while(($k,$v) = each %ENV ) { s/\${?$k}?/$v/ }; 
    s/\${[^-]*-([^}]*)}/$1/g' input

这个输入有问题,比如$ {FOO = some-text}。为了可靠地获取所有sh构造($ {word:rhs},其中':'可以是' - ','?','=','+','%','#'或任何相同的冒号前缀(或许多其他符号,如果你允许非posix sh语法!))你将不得不构建一个相当精细的比较集。

答案 3 :(得分:1)

我最近找到了一种使用 envsubst 执行此操作的方法:

export MYNAME="Jason"
echo '{ "status": 200, "message": { "name": "$MYNAME" } }' > my.json.template

cat my.json.template
# outputs { "status": 200, "message": { "name": "$MYNAME" } }    

cat my.json.template | envsubst
# outputs { "status": 200, "message": { "name": "Jason" } }

如果您没有 envsubst,您可以在 debian 发行版上安装它:

apt-get install gettext-base