定義された変数(シェル変数や環境変数)のみをbashで印刷する方法


57

bash組み込みコマンドはset、引数なしで呼び出された場合、すべてのシェル変数と環境変数を出力しますが、すべての定義済み関数も出力します。これにより、出力が人間にとって使用できなくなりにくくなりgrepます。

bash組み込みコマンドにset、関数ではなく変数のみを出力させるにはどうすればよいですか?

関数なしでシェル変数のみを出力する他のコマンドはありますか?

注:bashは、シェル変数と環境変数を区別します。こちらをご覧ください環境変数とbashでエクスポートされた環境変数の違い

回答:


51

「関数なしでシェル変数のみを出力する他のコマンドはありますか?」

man bashでは、セクションSHELL BUILTIN COMMANDS(setセクション)で、「posixモードでは、シェル変数のみが一覧表示されます。」

(set -o posix; set)

注:()フォークを好まない場合は、より冗長なバージョンを使用するだけで、構文はサブシェルを生成します

set -o posix; set; set +o posix

1
断然最良の解決策
ルスラン

1
始まる通常、興味のない変数の束があります_取り除くのは簡単です、:(set -o posix ; set | grep -v ^_)
ハイド

これも長い間私を悩ませてきました!複数行の値がある場合、_で始まる行を削除するだけでは十分ではありませんが、値の内容はそのまま残ります。:セットが順番に行を出力するので、あなたは、単に使用して、最初の_行の後に結果をカットすることができますので、すべての_行が、最後になりますset -o posix; set | sed -e '/^_/,$d'; set +o posix;
スコット・

1
注:括弧はで重要です(set -o posix; set)。括弧がないと、現在のBashシェルの動作がPosix標準に一致するように変更されます。(Dunnoの意味ですが、重要に見えます。)括弧を使用すると、Bashは変更されません。
ジョンレッド

1
副作用:設定POSIXLY_CORRECT=yとは追加posix$SHELLOPTS
トム・ヘイル

31

回避策は次のとおりです。

$ comm -3 <(declare | sort) <(declare -f | sort)

壊す:

  1. declare 定義済みのすべての変数(エクスポートされているかどうかに関係なく)および関数を出力します。
  2. declare -f 関数のみを出力します。
  3. 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='()'
...

以下を使用して属性を切り取ることができます... cut:

$ 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行であるため、その出力をさらに処理するために使用することを非常に困難にします。おそらく、これを防ぐためにIFS-fuをいくつか実行できます。


を使用したさらに別の回避策compgen

$ compgen -v

bashビルトインcompgenは、補完スクリプトで使用することを目的としていました。このために、compgen -vすべての定義済み変数をリストします。欠点:値ではなく変数名のみがリストされます。

値をリストするハックもあります。

$ compgen -v | while read var; do printf "%s=%q\n" "$var" "${!var}"; done

利点:それは純粋なbashソリューションです。欠点:を介した解釈のため、一部の値が台無しになりprintfます。また、パイプおよび/またはループからのサブシェルは、いくつかの余分な変数を追加します。


declare ...| cut変数の属性がない場合、パイプは壊れますか?私はそれ--がその場合に使用されていると推測していますが、私はまだ不安です。sedより安全かもしれません、すなわちdeclare -p | sed 's/^.* \([^ ]\+\)$/\1/'
jmtd

+1 compgen:)
RSFalcon7 14年

13

typeset組み込みは、妙に(関数のみを表示するオプションを持っている-f)が、パラメータのみを表示しません。幸いなことに、typeset(またはset)は、すべての関数、関数およびパラメーター名に改行または等号を含めることができず、パラメーター値の改行が引用符で囲まれる前にすべてのパラメーターを表示します(それらはとして表示されます\n)。したがって、等号を含まない最初の行で停止できます。

set | awk -F '=' '! /^[0-9A-Z_a-z]+=/ {exit} {print $1}'

これは、パラメーター名のみを出力します。値が必要な場合は、に変更print $1print $0ます。

これは、環境変数(「環境変数」は「エクスポートされたパラメーター」と同義です)ではなく、すべてのパラメーター名(ここではパラメーターと変数が同義で使用されます)を出力することに注意してください。

また、これは、パラメーター名に対するbashの制約に一致しない名前の環境変数がないことを前提としていることに注意してください。このような変数はbash内で作成することはできませんが、bashの開始時に環境から継承されている可能性があります。

env 'foo ()
{
  =oops' bash

素晴らしい解決策!「=」のない最初の行で停止することすら考えていませんでした。+1
スティーブンD

同等に、sedで: set | sed '/=/!Q'
トビー・スペイト

7

どのようにしてset変数のみを印刷することができるかわかりません。しかし、の出力を見ると、set変数だけを取得しているように見える次のものを見つけることができました。

$ set | grep "^\([[:alnum:]]\|[[:punct:]]\)\+=" 

基本的に、文字、数字、または句読点で始まり、その後に「=」が続く行を探しています。私が見た出力から、これはすべての変数を取得します。ただし、これは非常に移植性があるとは思えません。

タイトルが示唆するように、エクスポートされた変数をこのリストから減算して、エクスポートされていない変数のリストを取得したい場合、次のようなことができます

$ set | grep "^\([[:alnum:]]\|[[:punct:]]\)\+=" | sort > ./setvars && env | sort | comm -23 ./setvars - 

これを少し分解するために、次のようにします。

  1. set | grep "^\([[:alnum:]]\|[[:punct:]]\)\+=" | sort > ./setvars :これにより、すべての変数(前述)を取得し、それらを並べ替え、結果をファイルに貼り付けることができます。
  2. && env | sort:前のコマンドが完了したら、envその出力を呼び出して並べ替えます。
  3. | comm -23 ./setvars -:最後に、私たちはパイプのソートされた出力envcommして使用し-23、この場合には、セットから私たちの出力にユニークなラインを最初の引数にユニークなラインを印刷するオプションを選択します。

完了したら、コマンドで作成した一時ファイルをクリーンアップすることができます。 rm ./setvars


コマンドの問題は移植性ではありません(もちろんbashに固有ですが、grep側には問題はありません)。問題は、関数定義のいくつかの行を取得していることです。Bashは関数コードの大部分をインデントしますが、すべてではありません。特にここドキュメント内のテキスト(f () {|cat <<EOF|foo=bar|EOF|}ここで|、改行は表します)はインデントしません。
ジル「SO-悪であるのをやめる」

6

コマンドを使用するだけenvです。関数を印刷しません。


1
スクリプト内で使用された場合は実行されます。
-DocSalvager

2

コマンドprintenvを試してください。

$printenv

6
printenvおよびenvは、エクスポートされた(環境)変数のみを出力し、エクスポートされていない(シェル)変数は出力しません。
-Lri

@Lriありがとう!エクスポートされた変数だけを印刷する方法を考えました。
マークスチュワート


0

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複雑すぎます


0

受け入れられた答えは素晴らしいです。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 

両方とも、最初の関数がリストされているときに発生する '='文字のない行を見つけるまで行をダンプすることで機能します。後者は割り当てを切り取ります。

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