2009-08-20 107 views
57

在我的bash腳本中,有很多變量,我必須做些什麼才能將它們保存到文件中。 我的問題是如何列出我的腳本聲明的所有變量,並得到這樣的名單:如何列出在bash腳本中聲明的變量?

VARIABLE1=abc 
VARIABLE2=def 
VARIABLE3=ghi 

回答

102

set將輸出變量,遺憾的是它也將輸出功能定義爲好。

幸運的是POSIX模式只能輸出變量:

(set -o posix ; set) | less 

管道到less,或重定向到您想要的選項。

所以在短短的腳本時聲明的變量:

(set -o posix ; set) >/tmp/variables.before 
source script 
(set -o posix ; set) >/tmp/variables.after 
diff /tmp/variables.before /tmp/variables.after 
rm /tmp/variables.before /tmp/variables.after 

(或者至少一些基於該:-))

+0

我在發佈時進行了編輯。用'-o posix'調用好的差異將只包含變量。 – ezpz 2009-08-20 10:50:44

+6

不使用臨時文件:'VARS =「\'set -o posix; set \'」;源腳本; SCRIPT_VARS =「\'grep -vFe」$ VARS「<<<」$(set -o posix; set)「| grep -v^VARS = \'」;未設置VARS;'。這也會輸出儲存在現成格式中的變量。該列表將包含腳本更改的變量(取決於這是否合意) – 2011-08-15 22:12:26

+0

不幸的是,posix模式也會輸出不可修改的變量,因此您無法「輸出」它的輸出並將它們全部讀回。 – 2013-12-26 21:20:56

3

如果你能後置處理,(前面已經提到)您可能只需在腳本的開頭和結尾放置一個set調用(每個調用一個不同的文件),然後對這兩個文件執行diff操作。意識到這仍然會包含一些噪音。

你也可以用編程方式做到這一點。要將輸出限制在當前範圍內,您必須實現一個包裝到變量創建。例如

store() { 
    export ${1}="${*:2}" 
    [[ ${STORED} =~ "(^|)${1}($|)" ]] || STORED="${STORED} ${1}" 
} 

store VAR1 abc 
store VAR2 bcd 
store VAR3 cde 

for i in ${STORED}; do 
    echo "${i}=${!i}" 
done 

其中產量

VAR1=abc 
VAR2=bcd 
VAR3=cde 
0

嘗試使用腳本(可以稱之爲 「ls_vars」):

#!/bin/bash 
    set -a 
    env > /tmp/a 
    source $1 
    env > /tmp/b 
    diff /tmp/{a,b} | sed -ne 's/^> //p' 

使用chmod + X吧,:

ls_vars your-script.sh > vars.files.save 
+2

這不顯示局部變量,只顯示出口變量。 – 2010-11-01 19:50:24

8
for i in _ {a..z} {A..Z}; do eval "echo \${[email protected]}" ; done | xargs printf "%s\n" 

這必須打印所有shell變量名稱。您可以在獲取文件之前和之後獲得一個列表,就像使用「set」來區分哪些變量是新的(如其他答案中所解釋的)。但請記住,使用diff進行過濾可以過濾掉某些需要的變量,但在獲取文件之前已經存在。

在你的情況,如果你知道你的變量的名字開始與‘變量’,則可以輸出腳本,做:

for var in ${[email protected]}; do 
    printf "%s%q\n" "$var=" "${!var}" 
done 

UPDATE:對於純BASH解決方案(不使用外部命令):

for i in _ {a..z} {A..Z}; do 
    for var in `eval echo "\\${[email protected]}"`; do 
     echo $var 
     # you can test if $var matches some criteria and put it in the file or ignore 
    done 
done 
0

從安全角度來看,無論是@ akostadinov的answer或@ JuvenXu的answer優選依賴於所述set命令的非結構化輸出,由於以下潛在的安全漏洞:

#!/bin/bash 

function doLogic() 
{ 
    local COMMAND="${1}" 
    if (set -o posix; set | grep -q '^PS1=') 
    then 
     echo 'Script is interactive' 
    else 
     echo 'Script is NOT interactive' 
    fi 
} 

doLogic 'hello' # Script is NOT interactive 
doLogic $'\nPS1=' # Script is interactive 

上述功能doLogic用途set檢查是否存在變量PS1以確定腳本是否是交互式的(不必介意這是否是實現該目標的最佳方法;這僅僅是一個示例。)

然而,set的輸出是非結構化的,這意味着包含換行符的任何變量都可能完全污染結果。

這當然是潛在的安全風險。相反,使用Bash支持間接變量名稱擴展或compgen -v

-1

嘗試這種情況:set | egrep "^\w+="(帶或不帶| less管道)

第一提出的解決方案,(set -o posix ; set) | less,工作原理,但有一個缺點:它發送的控制代碼給所述終端,因此它們不正確顯示。因此,舉例來說,如果有(可能)一個IFS=$' \t\n'變量,我們可以看到:

IFS=' 
' 

...相反。

我的egrep解決方案正確顯示此(最終其他類似的)

+0

已經8年了,你知道 – lauriys 2017-03-09 15:22:26

+0

** Downvoted,因爲它明顯錯誤**'bash -c $'a(){echo「\ nA = B」; };未設A; set | egrep「^ \ w + =」'| grep^A'顯示'A = B「' - >失敗! – Tino 2017-12-30 11:19:31

0

我可能已經被盜the answer前一陣子......作爲FUNC反正稍有不同:

## 
    # usage source bin/nps-bash-util-funcs 
    # doEchoVars 
    doEchoVars(){ 

     # if the tmp dir does not exist 
     test -z ${tmp_dir} && \ 
     export tmp_dir="$(cd "$(dirname $0)/../../.."; pwd)""/dat/log/.tmp.$$" && \ 
     mkdir -p "$tmp_dir" && \ 
     (set -o posix ; set)| sort >"$tmp_dir/.vars.before" 


     (set -o posix ; set) | sort >"$tmp_dir/.vars.after" 
     cmd="$(comm -3 $tmp_dir/.vars.before $tmp_dir/.vars.after | perl -ne 's#\s+##g;print "\n $_ "')" 
     echo -e "$cmd" 
    } 
3

基於上面的一些答案,這個工作對我來說:

before=$(set -o posix; set | sort); 

源文件

comm -13 <(printf %s "$before") <(set -o posix; set | sort | uniq) 
0

這裏是如此mething類似@GinkgoFr答案,但沒有和@Tino或@DejayClayton, 發現的問題比@ DouglasLeeder的聰明set -o posix位更穩健:

+ function SOLUTION() { (set +o posix; set) | sed -ne '/^\w\+=/!q; p;'; } 

不同的是,該解決方案的第一個非後停止變量報告,例如第一個功能set

順便說一句:「Tino」問題已解決。儘管POSIX已關閉,並且功能由set, 報告,但該解決方案的sed ...部分僅允許通過可變報告(例如VAR=VALUE行)。 特別是,A2確實不是虛假地把它變成輸出。

+ function a() { echo $'\nA2=B'; }; A0=000; A9=999; 
+ SOLUTION | grep '^A[0-9]=' 
A0=000 
A9=999 

和:在「DejayClayton」問題得到解決(在變量值的嵌入式換行符做破壞輸出 - 每個VAR=VALUE得到一個輸出線):

+ A1=$'111\nA2=222'; A0=000; A9=999; 
+ SOLUTION | grep '^A[0-9]=' 
A0=000 
A1=$'111\nA2=222' 
A9=999 

注:該解決方案由@DouglasLeeder提供的「DejayClayton」問題(嵌入換行符的值)。 下面,A1是錯誤的,A2根本不應該顯示。

$ A1=$'111\nA2=222'; A0=000; A9=999; (set -o posix; set) | grep '^A[0-9]=' 
A0=000 
A1='111 
A2=222' 
A9=999 

最後:我不認爲bash的版本很重要,但它可能。我做了我的測試/在這一個發展:

$ bash --version 
GNU bash, version 4.4.12(1)-release (x86_64-pc-msys) 

後腳本:鑑於一些在OP對方答覆,我留下< 100%肯定set總是轉換值內換行到\n,這個解決方案依靠避免「DejayClayton」問題。也許這是一種現代行爲?還是編譯時間的變化?或者set -oshopt選項設置?如果知道這樣的變化,請添加評論...