2011-05-17 25 views
3

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

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

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

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

猫只是读取文件,我想$ HOME以某种方式通过猫在这里扩大,因为该文件将包含变量名(不喜欢HOME = /家/我自己)

我的问题是,如果这是可能的,否则我将不得不写一些脏代码。

编辑:它们是含有大的XML文件

<checkbox active="$value"> 

真或假

+1

'echo \'cat/tmp/home \''会吗? – Beta 2011-05-17 01:38:38

+0

真正包含的文件是什么?只有一个变量名?或者你是否试图想出一些可以将变量值插入自由格式文本的模板引擎? – sarnold 2011-05-17 01:42:43

+0

Beta @ nay ...; sarnold @大xml文件包含“”true或false。我将从/ etc中的其他文件中获取值 – 2011-05-17 01:43:34

回答

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 
+0

谢谢,但这需要我学习python:几乎没有。b – 2011-05-17 02:00:41

+0

几乎没有。我很快就会为你写代码,你会看到它很简单。 – 2011-05-17 02:04:26

+0

谢谢,不客气! – 2011-05-17 02:11:20

1

cat拷贝它的输入不变,其输出 - 至少在它的原始(第1版UNIX)的形式。它没有任何选择。然后BSD加了一大堆,原来的UNIX团队反对:'cat从伯克利挥舞着旗帜'回来(见:1 - passim)。它不应该被用来编辑文件 - 这不是它的目的。 (我在BSD(Mac OS X)手册页中找到了有关cat的文章:Rob Pike,“UNIX Style或cat -v Considered Harmful”,USENIX Summer Conference Proceedings,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; 
} 

当我包含在捕获字面$,代行操作没有正常工作。

+0

是的,我看了一下猫手册页,它的目的只是为了读取文件,虽然它可以用来写文件与重定向。你的脚本也很好,谢谢! – 2011-05-17 03:43:26

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元字符,并做了,而读/循环:

 
$ 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},':'可以是' - ','?','=','+','%','#'或任何与冒号前缀相同(或许多其他符号,如果你允许non-posix sh语法!))你将不得不构建一套相当复杂的比较。

+0

这就是我正在想的。如果我使用sed命令,我可以使用所有bash结构(我是一种bashist,并且在这些脚本中portabillity不是问题)。我在你的sed命令中发现的问题是,所有双引号(即“\”)都消失了,XML需要active =“true”,并且在active = true时失败,我需要保留来自XML的引号, *不包含变量,我们该如何改进这个sed命令? – 2011-05-18 04:18:36

+0

@Teresa只需在要逃脱的字符列表中添加“就可以了。不过,我认为我会坚持使用perl,因为评估未知输入的可能后果可能非常严重。 – 2011-05-18 09:30:35

+0

嗯,好吧,我会坚持perl,谢谢! – 2011-05-18 09:44:43