2011-05-17 21 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