web-dev-qa-db-ja.com

$ BASH_COMMAND変数は何に適していますか?

Bashマニュアル によると、環境変数BASH_COMMANDには

シェルがトラップの結果としてコマンドを実行していない限り、現在実行中または実行されようとしているコマンド。この場合、コマンドはトラップの時点で実行されているコマンドです。

そのトラップコーナーケースを別として、私が正しく理解していれば、これはコマンドを実行するときに変数BASH_COMMANDにそのコマンドが含まれることを意味します。その変数がコマンドの実行後に設定解除されるかどうかは明確ではありません(つまり、空いているwhileコマンドが実行されているが、実行されていない)。 現在実行中、またはabout to be]実行」というコマンドは、コマンド[just was was]実行ではありません。

しかし、チェックしましょう:

$ set | grep BASH_COMMAND=
$ 

空の。私はBASH_COMMAND='set | grep BASH_COMMAND='または多分BASH_COMMAND='set'を見ることを期待していましたが、空は驚きました。

他のことを試してみましょう:

$ echo $BASH_COMMAND
echo $BASH_COMMAND
$ 

それは理にかなっています。コマンドecho $BASH_COMMANDを実行すると、変数BASH_COMMANDには文字列echo $BASH_COMMANDが含まれます。今回はなぜ機能しましたが、以前は機能しませんでしたか?

もう一度setことをしましょう:

$ set | grep BASH_COMMAND=
BASH_COMMAND='echo $BASH_COMMAND'
$

待ってwasそのechoコマンドを実行したときに設定され、was後に設定解除されました。しかし、setを再度実行すると、BASH_COMMANDなかったsetコマンドに設定されました。ここでsetコマンドをどれだけ頻繁に実行しても、結果は変わりません。では、echoを実行するときに変数は設定されますが、setを実行するときは設定されませんか?どれどれ。

$ echo Hello AskUbuntu
Hello AskUbuntu
$ set | grep BASH_COMMAND=
BASH_COMMAND='echo $BASH_COMMAND'
$

What?したがって、echo $BASH_COMMANDを実行したときに変数が設定されましたが、echo Hello AskUbuntuを実行したときにnotになりました。今の違いはどこですか?変数は、現在のコマンド自体が実際にシェルに変数を評価させるときにのみ設定されますか?別の何かを試してみましょう。おそらく、変更のためのbashビルトインではなく、今度は外部コマンドがいくつかあります。

$ /bin/echo $BASH_COMMAND
/bin/echo $BASH_COMMAND
$ set | grep BASH_COMMAND=
BASH_COMMAND='/bin/echo $BASH_COMMAND'
$

うーん、また...変数が設定されました。私の現在の推測は正しいですか?変数は、評価が必要な場合にのみ設定されますか?どうして? なぜ?パフォーマンス上の理由から?もう一度試してみましょう。ファイル内の$BASH_COMMANDをgrepしようとしますが、$BASH_COMMANDgrepコマンドを含む必要があるため、grepはそのgrepコマンドをgrepする必要があります(すなわち、それ自体)。それでは、適切なファイルを作成しましょう。

$ echo -e "1 foo\n2 grep\n3 bar\n4 grep \$BASH_COMMAND tmp" > tmp
$ grep $BASH_COMMAND tmp
grep: $BASH_COMMAND: No such file or directory
tmp:2 grep                                      <-- here, the Word "grep" is RED
tmp:4 grep $BASH_COMMAND tmp                    <-- here, the Word "grep" is RED
tmp:2 grep                                      <-- here, the Word "grep" is RED
tmp:4 grep $BASH_COMMAND tmp                    <-- here, the Word "grep" is RED
$ set | grep BASH_COMMAND=
BASH_COMMAND='grep --color=auto $BASH_COMMAND tmp'
$

面白いですね。コマンドgrep $BASH_COMMAND tmpgrep grep $BASH_COMMAND tmp tmpに展開されました(もちろん、変数はその1回だけ展開されます)。したがって、$BASH_COMMANDに1回、grepを追加しました。存在せず、ファイルtmpに2回存在します。

Q1:私の現在の仮定は正しいですか:

  • BASH_COMMANDは、コマンドが実際に評価しようとしたときにのみ設定されます。そして
  • それはnotコマンドの実行後に設定解除されますが、説明によってそう信じられるかもしれませんか?

Q2:はいの場合、なぜですか?パフォーマンス?いいえの場合、上記のコマンドシーケンスの動作は他にどのように説明できますか?

Q3:最後に、この変数を実際に有意義に使用できるシナリオはありますか?私は実際に$Prompt_COMMAND内でそれを使用して実行中のコマンドを分析しようとしていました(そしてそれに応じていくつかのことを行います)が、私は_$Prompt_COMMAND内ですぐに、変数$BASH_COMMANDを見るコマンド。変数はそのコマンドにセッ​​トを取得します。 MYVARIABLE=$BASH_COMMANDの先頭で$Prompt_COMMANDを実行しても、割り当てもコマンドであるため、MYVARIABLEには文字列MYVARIABLE=$BASH_COMMANDが含まれます。 (この質問は、$Prompt_COMMAND実行内で現在のコマンドを取得する方法に関するものではありません。他の方法もあります。)

ハイゼンベルクの不確実性原理と少し似ています。変数を観察するだけで、変更します。

25
Malte Skoruppa

3番目の質問への回答:もちろん、Bashマニュアルで明確に示唆されている方法で意味のある方法で使用できます。 g .:

$ trap 'echo ‘$BASH_COMMAND’ failed with error code $?' ERR
$ fgfdjsa
fgfdjsa: command not found
‘fgfdjsa’ failed with error code 127
$ cat /etc/fgfdjsa
cat: /etc/fgfdjsa: No such file or directory
‘cat /etc/fgfdjsa’ failed with error code 1
15

Q3が回答されたので(私の意見では、BASH_COMMANDはトラップで有用であり、他のどこにもほとんどありません)、Q1とQ2を試してみましょう。

Q1の答えは次のとおりです。あなたの仮定の正しさは決定できません。彼らが不特定の行動について尋ねるので、どちらの箇条書きの真実も確立することができません。その仕様により、BASH_COMMANDの値は、そのコマンドの実行中にコマンドのテキストに設定されます。仕様には、他の状況、つまりコマンドが実行されていない場合にその値がどうあるべきかは明記されていません。任意の値を設定することも、まったく設定しないこともできます。

Q2「いいえの場合、上記のコマンドシーケンスの動作を他にどのように説明できますか?」その後、論理的に(多少は教育的であれば)続きます:BASH_COMMANDの値が未定義であるという事実によって説明されます。その値は未定義であるため、任意の値を持つことができます。これは、シーケンスが示すものです。

ポストスクリプト

確かに仕様でソフトスポットをヒットしていると思う点が1つあります。あなたが言うところです:

$ Prompt_COMMANDの先頭でMYVARIABLE = $ BASH_COMMANDを実行しても、MYVARIABLEには文字列MYVARIABLE = $ BASH_COMMANDが含まれます。これは割り当てもコマンドであるためです

Bashのmanページの読み方、斜体の部分は正しくありません。セクションSIMPLE COMMAND EXPANSIONでは、最初にコマンドラインでの変数の割り当てがどのように確保されるかを説明し、次に

コマンド名がない場合(つまり、変数の割り当てのみがあった場合)、変数の割り当ては現在のシェル環境に影響します。

これは、他のプログラミング言語のように、変数の割り当てがコマンドではない(したがって、BASH_COMMANDに表示されない)ことを示唆しています。これは、setの出力にBASH_COMMAND=set行がない理由も説明します。setは、本質的に変数割り当ての構文 'マーカー'です。

OTOH、そのセクションの最後の段落で

展開後にコマンド名が残っている場合、実行は以下のように進行します。それ以外の場合、commandは終了します。

...これは別の方法を示唆しており、変数の割り当てもコマンドです。

6
zwets

$ BASH_COMMANDの独創的な使用

最近、これを発見しました $ BASH_COMMANDの印象的な使用 マクロのような機能の実装に。

これはエイリアスのコアトリックであり、DEBUGトラップの使用を置き換えます。 DEBUGトラップに関する以前の投稿の一部を読むと、$ BASH_COMMAND変数を認識できます。その投稿で、DEBUGトラップの各呼び出しの前にコマンドのテキストに設定されていると述べました。まあ、すべてのコマンド、DEBUGトラップ、またはnoの実行前に設定されていることがわかります(たとえば、「echo“ this command = $ BASH_COMMAND”」を実行して、話している内容を確認します)。変数を(その行だけに)割り当てることにより、コマンド全体を含むコマンドの最も外側のスコープでBASH_COMMANDをキャプチャします。

著者の 前の記事 は、DEBUG trapを使用してテクニックを実装する際の良い背景を提供します。 trapは、改良版では削除されました。

2
DocSalvager

Trap ... debugの一般的な使用法は、「スクリーン」を使用しているときにウィンドウリスト(^ A ")に表示されるタイトルを改善することです。

「画面」、「ウィンドウリスト」をもっと使いやすくしようとしていたので、「トラップ...デバッグ」を参照する記事を見つけ始めました。

Prompt_COMMANDを使用して「null title sequence」を送信するメソッドがあまりうまく機能しないことがわかったため、trap ... debugメソッドに戻りました。

方法は次のとおりです。

1「shelltitle '$ | bash:'」を「$ HOME/.screenrc」に入れることにより、「screen」にエスケープシーケンスを検索する(有効にする)ように指示します。

2デバッグトラップのサブシェルへの伝播をオフにします。これは重要です。有効になっている場合、すべてが台無しになるため、「set + o functrace」を使用してください。

3「screen」のタイトルエスケープシーケンスを送信して、解釈します。trap 'printf "\ ek $(date +%Y%m%d%H%M%S)$(whoami)@ $(hostname):$(pwd) $ {BASH_COMMAND}\e\"'" DEBUG "

完全ではありませんが、役立ちます。このメソッドを使用して、文字通り好きなものをタイトルに入れることができます

次の「ウィンドウリスト」(5画面)を参照してください。

Num Name Flags

1 bash:20161115232035 mcb @ ken007:/ home/mcb/ken007 RSYNCCMD = "Sudo rsync" myrsync.sh -R -r "$ {1}" "$ {BACKUPDIR} $ {2:+"/$ {2} " } "$ 2 bash:20161115230434 mcb @ ken007:/ home/mcb/ken007 ls --color = auto -la $ 3 bash:20161115230504 mcb @ ken007:/ home/mcb/ken007 cat bin/psg.sh $ 4 bash: 20161115222415 mcb @ ken007:/ home/mcb/ken007 ssh ken009 $ 5 bash:20161115222450 mcb @ ken007:/ home/mcb/ken007 mycommoncleanup $

0