スクリプトで宣言された変数をbashでリストする方法は?


98

bashのスクリプトには多くの変数があり、それらをファイルに保存するために何かを作成する必要があります。私の質問は、スクリプトで宣言されたすべての変数をリストし、次のようにリストを取得する方法です。

VARIABLE1=abc
VARIABLE2=def
VARIABLE3=ghi

回答:


151

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

(または少なくともそれに基づいたもの:-))


投稿中に編集しました。-o posixnowを使用した素敵な呼び出しでは、diffには変数のみが含まれます。
ezpz 2009

8
一時ファイルを使用せず:VARS="`set -o posix ; set`"; source script; SCRIPT_VARS="`grep -vFe "$VARS" <<<"$(set -o posix ; set)" | grep -v ^VARS=`"; unset VARS;。これにより、変数がすぐに保存できる形式で出力されます。リストには、スクリプトによって変更された変数が含まれます(これが望ましいかどうかによって異なります)
ivan_pozdeev '15

1
@ErikAronestyを使用して環境を再作成できるようにするsource場合は、の出力を使用して再作成できるようにする必要がありdeclare -pます。
シックス・

2
あなたは一時ファイルの使用に頼ることなく、差分(または任意の同様のコマンド)で前と後の環境を比較したい場合は、次のようにそうすることができます:before=$(set -o posix; set); dosomestuff; diff <(echo "$before") <(set -o posix; set)
シックス・

1
@Caesarいいえ、空でない配列のみを試しました。空の配列の場合は正しいです-それらは印刷されません。
ソコウィ


10
for i in _ {a..z} {A..Z}; do eval "echo \${!$i@}" ; done | xargs printf "%s\n"

これは、すべてのシェル変数名を出力する必要があります。"他の回答で説明されているように"どの変数が新しいかを比較する "set"と同じように、ファイルをソーシングする前後にリストを取得できます。ただし、diffを使用したこのようなフィルタリングでは、ファイルを調達する前に存在していた必要な変数を除外できることに注意してください。

あなたの場合、変数の名前が「VARIABLE」で始まることがわかっている場合は、スクリプトをソースとして実行できます。

for var in ${!VARIABLE@}; do
   printf "%s%q\n" "$var=" "${!var}"
done

更新:純粋なBASHソリューションの場合(外部コマンドは使用されません):

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

1
+1とワンライナーバージョン(単一の評価付き):eval "printf '%q\n' $(printf ' "${!%s@}"' _ {a..z} {A..Z})"
netj

4

上記の回答のいくつかに基づいて、これは私にとってうまくいきました:

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

ソースファイル

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

3

(すでに述べたように)後処理が可能な場合setは、スクリプトの最初と最後に(それぞれ別のファイルに)呼び出しを行い、2つのファイルを比較することができます。これにはまだノイズが含まれていることを認識してください。

プログラムでこれを行うこともできます。出力を現在のスコープのみに制限するには、変数の作成にラッパーを実装する必要があります。例えば

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

2

これは@GinkgoFrの回答に似ていますが、@ Tinoまたは@DejayClaytonによって識別される問題がなく、@ DouglasLeederの巧妙なset -o posixビットよりも堅牢です。

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

違いは、このソリューションは最初の非変数レポートの後に停止することです。たとえば、 set

ところで:「ティノ」の問題は解決されました。POSIXがオフになっていて、関数がによって報告されているset場合でもsed ...、ソリューションの一部では、変数の報告(例:VAR=VALUE行)のみが許可されます。特に、は誤って出力に入れA2ませ

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

AND:「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)

POST-SCRIPT:OPへの他のいくつかの応答を考えると、値内の改行をset 常にに変換することは100%未満\nであり、「DejayClayton」の問題を回避するためにこのソリューションはこれに依存しています。おそらくそれは現代的な行動でしょうか?またはコンパイル時のバリエーション?またはA set -oまたはshoptオプション設定?そのようなバリエーション知っている場合、コメントを追加してください...


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 it、そして:

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

0

セキュリティの観点からは、どちらか@ akostadinovの答えや@ JuvenXuの答えはの構造化されていない出力に依存することが好ましい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

上記の関数doLogicset、変数の存在を確認するために使用しますPS1、スクリプトがインタラクティブかどうかを判断するため(これがその目的を達成するための最良の方法であるかどうかは気にしないでください。これは単なる例です。)

ただし、の出力 setは構造化されていません。つまり、改行を含む変数は結果を完全に汚染する可能性があります。

もちろん、これは潜在的なセキュリティリスクです。代わりに、Bashの間接変数名展開のサポート、またはを使用してくださいcompgen -v


0

これを試してください:(配管のset | egrep "^\w+="有無にかかわらず| less

最初に提案されたソリューションは( set -o posix ; set ) | less機能しますが、欠点があります。制御コードが端末に送信されるため、適切に表示されません。だから、例えば、存在する場合(おそらく)IFS=$' \t\n'変数は、我々が見ることができます:

IFS='
'

…代わりに。

私のegrep解決策はこれ(そして最終的には他の類似のもの)を適切に表示します。


それはあなたが知っている、8年ぶりだ
lauriys

明らかに間違った bash -c $'a() { echo "\nA=B"; }; unset A; set | egrep "^\w+="' | grep ^A表示であるため反対投票A=B" ->失敗!
Tino、

"_"(前のコマンドの最後の引数)疑似変数のみを意味するように見える奇妙なテストですが、他のテスト、特にIFSでは失敗しません。「bash -c」の下で実行しても、意味がありません。あなたは少なくとも反対投票の代わりに中立を保っていたはずです。
GingkoFr 2018

0

私はおそらく以前に答えを盗んだことがあります ...とにかく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"
    } 

0

printenvコマンド:

printenvすべてのenvironment variables値と一緒に出力します。

幸運を...


0

これを行う簡単な方法は、スクリプトを実行する前にシステム環境変数を設定してbash strictモードを使用し、diffを使用してスクリプトのものだけをソートすることです。

# Add this line at the top of your script :
set > /tmp/old_vars.log

# Add this line at the end of your script :
set > /tmp/new_vars.log

# Alternatively you can remove unwanted variables with grep (e.g., passwords) :
set | grep -v "PASSWORD1=\|PASSWORD2=\|PASSWORD3=" > /tmp/new_vars.log

# Now you can compare to sort variables of your script :
diff /tmp/old_vars.log /tmp/new_vars.log | grep "^>" > /tmp/script_vars.log

/tmp/script_vars.logでスクリプトの変数を取得できるようになりました。または少なくともそれに基づいた何か!


0

パーティーには少し遅れますが、ここに別の提案があります:

#!/bin/bash

set_before=$( set -o posix; set | sed -e '/^_=*/d' )

# create/set some variables
VARIABLE1=a
VARIABLE2=b
VARIABLE3=c

set_after=$( set -o posix; unset set_before; set | sed -e '/^_=/d' )
diff  <(echo "$set_before") <(echo "$set_after") | sed -e 's/^> //' -e '/^[[:digit:]].*/d'

差分+ sedの所望の形式ですべてのスクリプトに定義された変数を出力パイプラインコマンドライン(OPの後に指定されています)。

VARIABLE1=a
VARIABLE2=b
VARIABLE3=c
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.