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


25

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

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

そのトラップコーナーケースを別として、私が正しく理解していれば、これはコマンドを実行したときに変数BASH_COMMANDにそのコマンドが含まれていることを意味します。絶対にその変数は、コマンドの実行後に設定されていないかどうかはっきりしていない(つまり、唯一のavaialbleである一方、 1はそれがあるので、「コマンドがあると主張かもしれませんが、コマンドはなく、後に、実行されている)、現在実行中またはされようとして実行します」 、それはコマンドでないだけでた実行します。

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

$ 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'
$

待って それはされた私は、実行時に設定するechoコマンドを、そして、それはありませんでした、その後解除。しかし、私がset再び実行したとき、コマンドに設定されてBASH_COMMAND いませんでしたsetsetここでコマンドを実行する頻度に関係なく、結果は変わりません。では、実行時に変数が設定されますが、実行時には設定されechoませんsetか?どれどれ。

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

何?変数だから私は、実行時に設定されていたecho $BASH_COMMANDが、ではない私は、実行時にecho Hello AskUbuntu?今の違いはどこですか?変数は、現在のコマンド自体が実際にシェルに変数を評価させるときにのみ設定されますか?別の何かを試してみましょう。おそらく、変更のための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 tmpに拡大してしまったgrep grep $BASH_COMMAND tmp tmp、と私はのためにgrepped(変数はもちろん、一度だけのことを拡大します)grepファイルに一度、$BASH_COMMAND存在し、二回ファイルではありませんtmp

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

  • BASH_COMMANDコマンドが実際に評価しようとしたときにのみ設定されます。そして
  • それはない記述はそう信じるように私たちを導くことにもかかわらず、コマンドの実行後に解除?

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

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

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


5
素敵ですが、おそらくunix.stackexchange.comに適してます...本当のbashüber- gurusがあります。
Rmano 14

さて、そこに移動することは可能ですか?改造?
マルテスコルッパ14

どうすればいいのか本当にわかりません--- Modの特権だと思います。一方、フラグを立てることは賢明だとは思わない---誰かがクローズフラグに基づいて行動するかどうかを見てみましょう。
Rmano

1
3番目の点については、これがあなたが探しているものです。おそらくその記事に基づいて、最初の2つのポイントに対する答えも見つけることができます。
ラドゥラデアヌ14

2
+1は私を混乱させましたが、読むのは楽しかったです!
ジョー14

回答:


15

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

$ 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

ああ、本当にいい。だから、この変数が意味を持つ唯一のコンテキストはトラップであると言うでしょうか?これは、手動で、コーナーケースのように聞こえ:「コマンドが実行される(...)、シェルはトラップの結果としてコマンドを実行していない限り、 ...」
マルトSkoruppa

@DocSalvagerによる回答にリンクされた記事を読んだ後$BASH_COMMAND、トラップ以外のコンテキストでも実際に有意義に使用できることは明らかです。しかし、あなたが説明する使用法はおそらく最も典型的で簡単です。あなたの答え、そしてDocSalvagerの答えは、私のQ3に最もよく答えます。これは私にとって最も重要なことでした。Q1とQ2については、@ zwetsで示されているように、これらは未定義です。それはそれかもしれ$BASH_COMMANDまたは他のいくつかの奇妙な内部プログラムの条件はその行動につながる可能性-パフォーマンスのために、アクセスした場合にのみ値を与えています。知るか?
マルテスコルッパ14

1
副次的に、各コマンドの前に評価を強制することで、常に設定するように強制できることを発見しました。これを行うには、すべてのコマンド(すべてem)の前に実行されるDEBUGトラップを使用できます。私たちが発行した場合、例えば、は、必ず各コマンドの前に評価(およびその値が割り当てられます)。そのトラップがアクティブなときに実行すると...何を知っていますか?予想どおり、出力は$BASH_COMMAND$BASH_COMMANDtrap 'echo "$BASH_COMMAND" > /dev/null' DEBUG$BASH_COMMAND$COMMANDset | grep BASH_COMMAND=BASH_COMMAND=set
次のとおりです。)

6

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

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

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

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


1
何らかの仮定が確立できないからといって、それが間違っているという意味ではありません。アインシュタインは、相対性理論の基本的な仮説の1つとして、光の速度がどの観測者にとっても(任意の速度で)同じであると仮定しました。それは確立できませんが、これはそれが間違っているという意味ではありません。「確立できる」プロパティと「正しい」プロパティは直交しています。せいぜい「確立できないため、それが正しいかどうかわからない」と言うことができます。また、それがされて指定された:それは、実行時に現在のコマンドです。私が入力した場合のでset、私は見るべきBASH_COMMAND='set'その出力のどこかで、
マルタSkoruppa

...しかし、そうではありません。それがコマンドの実行中setであっても。したがって、仕様に従って動作するはずです。実装が仕様を忠実に守っていないということですか、それとも仕様を誤解しているのでしょうか?その質問への答えを見つけることは、Q1の目的の一種です。追記のために+1 :)
マルテスコルッパ

@MalteSkoruppa良い点。それに応じて答えを修正し、についてのコメントを追加しましたset
zwets

1
bashインタープリターでsetは、「コマンド」ではない可能性があります。同じように=「コマンド」ではありません。これらのトークンに続く/周囲のテキストの処理は、「コマンド」の処理とはまったく異なるロジックを持つことができます。
DocSalvager 14

両方の良い点。:)それはset「コマンド」として数えられないことでしょう。私は$BASH_COMMAND、多くの状況でそれがあまりにも指定されていないと判明することはなかったでしょう。少なくとも、manページは間違いなく明確であることを確立していると思います;)
Malte Skoruppa 14

2

$ BASH_COMMANDの独創的な使用

最近、マクロに似た機能を実装するにこの$ BASH_COMMANDの印象的な使用法が見つかりました。

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

著者の以前の記事は、DEBUGを使用してテクニックを実装する際の良い背景も提供していますtraptrap改良されたバージョンで除去されます。


+1最後に、これら2つの記事を読みました。うわー!なんて読め!非常に啓発的です その男はバッシュの第一人者です!称賛!また、これ$BASH_COMMANDは、a以外のコンテキストで有意義に使用できるかどうかに関するDmitryの回答に関する私のコメントに回答しますtrap。そして、それはなんという用途でしょう!それを使用してマクロコマンドをbashに実装します-誰がそれを考えていたでしょうか?ポインターをありがとう。
マルテスコルッパ14

0

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 $

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