web-dev-qa-db-ja.com

bashですべての非環境変数をリストする方法は?

Bash 3.2.52では、すべての非環境変数(すべて自己宣言された変数)をechoしたいのですが。

すべての変数を出力するこのコマンドを実行すると、理解できない出力が得られました。これは、すでに使用しているset -x && clear -rモードと競合しているようです。

diff -U 1 <(set -o posix ; set |cut -d= -f1) <(
    exec bash -ic 'set -o posix ; set' | cut -d= -f1)  |
        grep '^[-][^-]'                                |
        cut -d- -f2                                    |
        grep -vE '^(COLUMNS|HISTFILESIZE|HISTSIZE|LINES|PIPESTATUS)$'

このようなリストを作成するには、echoまたはprintf(またはその他の「より単純な」)操作が必要です。
このバージョンのBashで可能な場合、どのようにしてこれを達成できますか?

8
user149572

GNU Parallelにはenv_parallelが含まれています。 env_parallelの一部には、サポートされているシェルのすべての変数がリストされています。

bashの場合、このコードは次のとおりです。

_names_of_VARIABLES() {
    compgen -A variable
}
_bodies_of_VARIABLES() {
    typeset -p "$@"
}

したがって、すべての変数を指定して、ユーザーが設定した変数を特定する必要があります。我々はcanbashの特定のバージョンによって設定されたすべての変数をハードコーディングすることでそれを行いますが、bashは将来さらに多くの変数を設定する可能性があるため、これはあまり将来の証明にはなりませんバージョン($BASH_MYVARは、ユーザーまたはbashの将来のバージョンによって設定されますか?).

したがって、代わりにenv_parallelは、クリーンな環境を定義してenv_parallel --sessionを実行するように求めます。これは、前に定義された名前をリストすることによって$PARALLEL_IGNORED_NAMESを設定します(上記のコードを使用)。

ユーザーが変数を設定した環境で後で実行すると、クリーンな環境と現在の環境の違いを簡単に理解できます。

env_parallel --sessionを使用すると、セッションごとにクリーンな環境を定義できますが、セッション間で使用できる参照環境が必要な場合は、変数のリストをファイルに保存するだけです。そう:

# In clean envronment
compgen -A variable > ~/.clean-env-vars

# In environment with user defined vars
compgen -A variable | grep -Fxvf ~/.clean-env-vars

例えば:

#!/bin/bash

# In clean envronment
compgen -A variable > ~/.clean-env-vars

myvar=4
yourvar=3

# In environment with user defined vars
compgen -A variable | grep -Fxvf ~/.clean-env-vars

# This prints:
# myvar
# yourvar
# PIPESTATUS (which is set when running a pipe)
5
Ole Tange

これを~/.bashrcに追加してください

pre () {
    set -o posix;set > /tmp/tmp-original-envs
}

post () {
    set -o posix;set > /tmp/tmp-new-envs
    diff /tmp/tmp-original-envs /tmp/tmp-new-envs | grep -v BASH_LINENO | grep -v FUNCNAME | grep '>'
}

次に、変更の前にpreを実行し、後でpostを実行します

例:

[localhost]$ pre
[localhost]$ test=new
[localhost]$ post
> test=new
[localhost]$ 
2
intika

この解決策は、すべての非環境変数をリストする道へとあなたを導いてくれると思います。 ITEM=$'VALUE\nSTRANGE=QUARK'ALSO=$'VALUE\ndeclare -r LANG=fake'のように定義された変数、つまり改行が埋め込まれた変数を確実に処理します。

for item in $(declare -p | awk '$2 !~ /[aAx]/ && $3 ~ /.=/ {print substr($3,1,match($3,"=")-1)}')
do
    if [[ -n "$item" ]] && ! { env -0 | grep -q $'\0'"${item}="; }
    then
        printf ">> %s = %s <<\n" "$item" "${!item}"
        # printf "%s\n" "$item"
    fi
done

printfステートメントを調整して、変数名だけを出力したり、配列に追加したり、その他の必要なことを行うことができます。

0
roaima

私のbashバージョンは3.2.57です

私はset +o posixを使用します。これにより、各変数の定数が1行で表示されるように動作が変更されます

フィルタリングするにはsort| uniq -cを使用し、値を1 lに維持します

bash-3.2$ bar=" foobar= "
bash-3.2$ foo="0
> 1
> 2 "

今私は2つの変数がありますfoobar

bash-3.2$ A=$(  (  ( set +o posix ; set |cut -d= -f1 ) ; 
                   ( bash -ic 'set +o posix ; set |cut -d= -f1' )  
                ) | sort | uniq -c | sed 's/^ *1 //p;d' | 
               grep -vE '^(COLUMNS|HISTFILESIZE|HISTSIZE|LINES|PIPESTATUS|BASH_EXECUTION_STRING)$' )
bash-3.2$ echo $A
bar foo
0
EchoMike444

Kludgy、bashのみのソリューション:

(setn(){
   set | sed '/^{/,/^}/d;/=/!d;/^BASH[A-Z_]*=\|^PPID=\|^SHLVL=\|^PIPESTATUS=\|^HISTSIZE=\|^HISTFILESIZE=\|^_[a-z_]*=/d' | sort
}
export -f setn
comm -23 <(setn) <("$BASH" -ic setn))

sedを介して他の変数を除外する必要がある場合もあります(またはBASH..パターンをより厳密にする)。 /_[a-z_]*=/は、_backup_glob_xspecsなどのプログラム可能な補完によって定義された変数を除外することになっています。それももっと厳しくすることができます。

bashは、変な文字を含む変数の値を$'...'形式で出力するため、次のように処理する必要があります。

foo='
bar
baz
'
...
foo=$'\nbar\nbaz\n'

bashは、namesに改行が含まれているenvvarsからシェル変数を作成しないため、このハッキングをこのようなトリックで破る方法はありません。

0
mosvy

compgen -A variableを使用するソリューション で問題が発生したようです。質問の本文で言及したset -xのせいかもしれませんが、わかりません。


今はcompgenなし。 このコメント から始めましょう。それは言う:

grep -vxF -f <( declare -x -p ) <( declare -p )

部分的に改善します

grep -vxF -f <( declare -x -p | grep -o '[^ =]*=') <( declare -p | grep -o '[^ =]*=')

現在、いくつかの問題があります。

  1. コンテンツに=を含む変数は、上記のコードで誤検知を報告します。例:

    foo='123
    bar=baz
    =xyz'
    

    コードを実行します。 (特に)foo=bar=および=を出力します。これを修正するには、そのような変数が実際に存在するかどうかを各行でテストする必要があります。

  2. または、重複を取得することもできます。

    foo='123
    aaa foo=456
    bar=baz
    bar=qux'
    

    これを修正するには、sort -uを使用できます。私は最後に小文字の変数を取得するためにLC_COLLATE=POSIX sort -uを好みます。

  3. 上記のfooは、エクスポートされた場合、正当な(エクスポートされない)barを「マスク」できます。例:

    export foo
    bar=999
    

    現在、コードはbar=を出力しません。これを修正するには、「グローバル」declare -x -pに基づくことを除外しないでください。各変数について、エクスポートされていないかどうかを個別に確認する必要があります。この手順により、予備のgrep -vxFが不要になります。

したがって、この:

declare -p | grep -o '[^ =]*=' | LC_COLLATE=POSIX sort -u \
   | while IFS='=' read -r v ; do
      [ -v "$v" ] \
      && bash -c "[ ! -v '$v' ]" \
      && printf '%s\n' "$v"
done

注変数がエクスポートされるかどうかは厳密にはチェックしません。子に設定されているかどうかを確認しますbash。レポートされるインタラクティブシェルに固有の変数があります。手動で除外することもできます。または、bash -ic …を実行することもできます。しかし、複数回なので、さらに遅くなります。

誤検知なしですべての変数のリストを取得する信頼できる(?)方法があるため、grep -vxFの元のアイデアに戻り、子bashを1回だけ実行できます。次のスニペットは、bash -iで非常にうまく機能します。私の場合、手動で除外する変数はCOLUMNSLINESのみです。

( set +x
function _get_vars {
declare -p | grep -o '[^ =]*=' | LC_COLLATE=POSIX sort -u \
   | while IFS='=' read -r v ; do
      [ -v "$v" ] \
      && printf '%s\n' "$v"
   done
}
export -f _get_vars

_get_vars | grep -vxF -f <( bash -ic '_get_vars' ) \
| grep -vE '^(COLUMNS|LINES)$' )

念のため、サブシェルには意図的にset +xを使用しています。サブシェルは、関数を「ローカル」に保つのにも役立ちます(現在のシェルでは使用できません)。非インタラクティブな子bashとより多くのフィルタリングを好むかもしれません。これを必要に応じて調整してください。


たぶん、適切な場所にset +xを置くだけでcompgenアプローチがうまくいくでしょう。これはどう?

( set +x
compgen -A variable | grep -vxF -f <( bash -ic 'compgen -A variable' ) \
| grep -vE '^(COLUMNS|LINES)$' )

免責事項:Bash 3.2.52ではテストされていません。 4.4.12でテスト済み。

0

ニーズに応じて、1つの簡単な解決策は次のようになります:

  1. _set > tmp_または_set > /tmp/current_を使用して、変更前の現在の変数を保存します
  2. アプリケーションを変更/実行しますか
  3. diff -u <(cat tmp) <(set)で変更されたものを抽出する、または
_diff -u <(cat tmp) <(set) | tail -n +3 | grep -v PIPESTATUS | grep -v "_=" | grep -E "^\+"
_

どこ:

_tail -n +3_:diffコマンドの最初の不要な行を削除します

_grep -v PIPESTATUS | grep -v "_="_:不要な変数を削除

_grep -E "^\+"_:必要な/必要な変更のみを表示

代替:

_diff -u <(set -o posix; set) <(bash -lc 'set -o posix; set') | grep -E "^\+"
_

注:

あなたのスクリプトでは、execが完全に置き換えられることに注意してください。これから起動されるプロセスは、達成しようとしていることに干渉する可能性があります

0
intika

すべての自己宣言変数(すべての非環境変数)をエコーし​​たい

これは、私にとって、commのタスクです。

comm -23 <( set | cut -d= -f1 | sort ) <( env | cut -d= -f1 | sort )

-23は、commが列2および3の印刷を省略すべきであることを意味します。

3番目は両方のリストにあるエントリで、2番目はenvの後処理出力にのみあるエントリです。

または、IOW 最初のリストにあった一意のエントリのみを表示

P. S.一部のエントリは両方のリストで同時に見つけることができるため(comm -12 …)、あなたcouldもそれらを結果セットに含めたいです。つまり、-3その場合、3列目からの行は印刷時にシフトして表示されます。

0
poige