Bash組み込みコマンドset
を引数なしで呼び出すと、すべてのシェル変数と環境変数だけでなく、すべての定義済み関数も出力されます。これにより、出力が人間にとって使用できなくなり、grep
が困難になります。
Bash組み込みコマンドset
に関数ではなく変数のみを出力させるにはどうすればよいですか?
関数なしでシェル変数のみを出力する他のコマンドはありますか?
注:bashはシェル変数と環境変数を区別します。ここを参照 bashでの環境変数とエクスポートされた環境変数の違い
「関数なしで、シェル変数のみを出力する他のコマンドはありますか?」
Man bashでは、Shell BUILTIN COMMANDSセクション(setセクション内)に次のように書かれています。
(set -o posix; set)
注意: ()
シンタックスはサブシェルを生成しますが、フォークしたくない場合は、より詳細なバージョンを使用してください。
set -o posix; set; set +o posix
いくつかの回避策は次のとおりです。
$ comm -3 <(declare | sort) <(declare -f | sort)
壊す:
declare
は、定義されたすべての変数(エクスポートされているかどうかにかかわらず)および関数を出力します。declare -f
は関数のみを出力します。comm -3
は、両方に共通するすべての行を削除します。実際には、これにより関数のみが削除され、変数のみが残ります。エクスポートされない変数のみを出力するには:
$ comm -3 <(comm -3 <(declare | sort) <(declare -f | sort)) <(env | sort)
別の回避策:
$ declare -p
これは変数のみを出力しますが、いくつかの醜い属性を伴います。
declare -- BASH="/bin/bash"
declare -ir BASHPID=""
declare -A BASH_ALIASES='()'
declare -a BASH_ARGC='()'
...
次を使用して属性を切り取ることができます...切り取り:
$ declare -p | cut -d " " -f 3
1つの欠点は、IFSの値が表示される代わりに解釈されることです。
比較:
$ comm -3 <(declare | sort) <(declare -f | sort)
...
IFS=$' \t\n'
...
$ declare -p | cut -d " " -f 3
...
IFS="
"
...
そのため、1行に"
が1つしかないため、その出力を使用してさらに処理することは非常に困難です。おそらくこれを防ぐためにいくつかのIFS-fuを実行できます。
compgen
を使用したさらに別の回避策:
$ compgen -v
組み込みのbash compgen
は、補完スクリプトで使用するためのものでした。このため、compgen -v
はすべての定義済み変数をリストします。欠点:値ではなく、変数名のみが表示されます。
これも値をリストするハックです。
$ compgen -v | while read var; do printf "%s=%q\n" "$var" "${!var}"; done
利点:純粋なbashソリューションです。欠点:printf
による解釈のため、一部の値がめちゃくちゃになります。また、パイプおよび/またはループからのサブシェルは、いくつかの追加の変数を追加します。
typeset
組み込みには、奇妙なことに、関数のみを表示するオプションがあります(-f
)ただし、パラメータのみを表示することはできません。幸い、typeset
(またはset
)は、すべての関数の前にすべてのパラメーターを表示します。関数とパラメーターの名前に改行または等号を含めることはできません。パラメーター値の改行は引用符で囲まれます(これらは\n
)。したがって、等号を含まない最初の行で停止できます。
set | awk -F '=' '! /^[0-9A-Z_a-z]+=/ {exit} {print $1}'
これはパラメータ名のみを出力します。値が必要な場合は、print $1
からprint $0
。
これにより、環境変数だけではなく、すべてのパラメーター名(ここではパラメーターと変数が同義で使用されます)が出力されることに注意してください(「環境変数」は「エクスポートされたパラメーター」と同義です)。
これは、パラメーター名に対するbashの制約と一致しない名前の環境変数がないことを前提としていることにも注意してください。このような変数はbash内で作成することはできませんが、bashの起動時に環境から継承することができます。
env 'foo ()
{
=oops' bash
set
に変数のみを出力させる方法がわかりません。しかし、set
の出力を見ると、変数だけを取得しているように見える次の結果を見つけることができました。
_$ set | grep "^\([[:alnum:]]\|[[:punct:]]\)\+="
_
基本的に、文字、数字、または句読点で始まり、「=」が続く行を探しています。私が見た出力から、これはすべての変数を取得します。しかし、これは非常に移植性があるとは思えません。
タイトルが示すように、このリストからエクスポートされる変数を差し引いて、エクスポートされない変数のリストを取得する場合は、次のようにすることができます
_$ set | grep "^\([[:alnum:]]\|[[:punct:]]\)\+=" | sort > ./setvars && env | sort | comm -23 ./setvars -
_
これを少し分解するために、次のことを行います。
set | grep "^\([[:alnum:]]\|[[:punct:]]\)\+=" | sort > ./setvars
:うまくいけば、すべての変数を取得し(前述のとおり)、それらを並べ替え、結果をファイルに貼り付けます。&& env | sort
_:前のコマンドが完了したら、env
を呼び出してその出力を並べ替えます。| comm -23 ./setvars -
_:最後に、env
のソートされた出力をcomm
にパイプし、_-23
_オプションを使用して、最初の引数に固有の行を出力します。セットからの出力に固有の行を作成します。完了したら、コマンド_rm ./setvars
_で作成した一時ファイルをクリーンアップすることができます。
コマンドenv
を使用してください。関数は出力されません。
コマンドprintenvを試してください:
$printenv
Bashでは、これは変数名のみを出力します。
compgen -v
または、値も必要な場合は、次を使用します。
declare -p
受け入れられた答えは素晴らしいです。私はPOSIXモードの設定を含まない代替案を提供しています:
これは、関数の状態をファイルに保存して後で続行できるようにするために使用してきた手法です。 1つ目は状態ダンプを生成し、2つ目は変数名のリストのみを生成します。
set 2>/dev/null | while read a; do [[ $a == *=* ]] || break; echo $a; done
set 2>/dev/null | while read a; do [[ $a == *=* ]] || break; echo ${a/=*}; done
どちらも、最初の関数がリストされているときに発生する「=」文字のない行が見つかるまで行をダンプして機能します。後者は割り当てを切り取ります。
クリーンなシェルと比較して、rcスクリプトからの変数も除外されるようにする
## get mostly local vars
diff_env(){
diff <(bash -cl 'set -o posix && set') \
<(set -o posix && set && set +o posix) | \
grep -E "^>|^\+" | \
grep -Ev "^(>|\+|\+\+) ?(BASH|COLUMNS|LINES|HIST|PPID|SHLVL|PS(1|2)|Shell|FUNC)" | \
sed -r 's/^> ?|^\+ ?//'
}
comm
のバージョンは複雑すぎます