4

シェルでは、次のコマンドを問題なく実行します。

ls-al

!ls

フラグls付きのファイルもリストするための 2 番目の呼び出し。-alしかし、上記のスクリプトを bash スクリプトに入れると、クレームがスローされ、

!ls, command not found.

スクリプトで同じ効果を実現する方法は?

4

3 に答える 3

6

スクリプトでコマンド履歴と ! スタイルの履歴展開の両方を有効にする必要があります (非対話型シェルではデフォルトでどちらも無効になっています)。

set -o history
set -o histexpand

展開されたコマンドは、対話型シェルと同様に、標準エラーにもエコーされます。histverifyシェル オプション ( )をオンにすることでこれを防ぐことができますshopt -s histverifyが、非対話型シェルでは、履歴の展開が null-op になるようです。

于 2012-08-23T18:42:18.653 に答える
0

ええと、私はこれも機能させたかったので、このset -o history ; set -o histexpand方法はでは機能しないことをみんなに伝えなければなりませんbash 4.x。とにかく、これを達成するためのより良い方法があるため、そこで使用することを意図していません。

まず第一に、スクリプトで実行したいだけのかなり些細な例です: ( 4.x 以降のみ)historybash

#!/bin/bash -i
history

簡単な答え:うまくいきます!!
新しい-iオプション spanking はinteractiveの略で、動作しhistory ます。しかし、何の目的で?

OP からの Michael H. のコメントを引用し
ます。「これを有効にすることはできますが、これはプログラミングの実践としては不適切です。スクリプト (...) が理解しにくくなります。デフォルトで無効になっているのには理由があります。なぜこれをしたいですか?」

はい、なぜですか?これの深い意味は何ですか?それについては、次のセクションで説明します。

私のhistoryバッファーは巨大になりましたが、それらの行のいくつかはスクリプトのワンライナーであり、毎回再入力したくありません。しかし、場合によっては、これらの行を少し変更したいこともあります。これは、以前は合計で 2 つしか必要としなかったのに対し、おそらく 3 番目のパラメーターを指定したいからです。したがって、 4.0+ 機能を使用してを呼び出す理想的な方法は次のとおりです。bash history

$ history
 (...)
 <lots of lines>
 (...)
  1234 while IFS='whatever' read [[ $whatever -lt max ]]; do ... ; done < <(workfile.fil)
 <25 more lines>

したがって、履歴からの1234は、まさに私たちが望む行です。確かに、マウスを持ってそこに移動し、行全体を一次バッファに入れることはできますか? しかし、私たちは *NIX を使用しています。これが、以下の小さなスクリプトを書いた理由です。繰り返しますが、これはbash4.0 以降専用です (ただしbash、前述のものを使用して 3.x およびそれ以前のバージョンに適応する可能性がありますset -o ......)

#!/bin/bash -i
[[ $1 == "" ]] || history | grep "^\s*$1" | 
awk '{for (i=2; i<=NF; i++) printf $i" "}' | tr '\n' '\0'

たとえば、これを保存するとxselauto.sh、呼び出すことができます

$ ./xselauto.sh 1234

history行番号 1234の内容がプライマリ バッファに格納され、再利用の準備が整います。それでも誰かが「これには目的がありません AFAICS」または「誰がこの機能を必要とするでしょうか?」と言う場合。- わかりました、気にしません。しかし、複雑な行を毎回再入力するのが面倒なので、この機能なしでは生きていきたくありません。そして、履歴からマークされた行ごとにマウスに触れたくありません.TBH. これは、そのxselために書かれたものです。

ところで、パイプの一部は、コマンドが実行されtrないようにするダーティハックです。「危険な」コマンドの場合、ユーザーがキーを押して実行する前に、常にユーザーに見えるようにしておくことが非常に重要です。省略しても構いませんが・・・注意されました。Enter


PS このスクリプトレットは実際には回避策!1234であり、bash シェルでの入力をシミュレートします。スクリプトで直接!作業を行うことはできなかったので(履歴行 1234の内容を明らかにすることはできませんでした)、コピーしたい行を ing するだけで問題を回避しました。echogrep

于 2014-12-09T17:33:02.717 に答える
-2

履歴の拡張は、スクリプト言語の一部ではなく、シェルのインタラクティブなコマンドライン編集機能の一部です。スクリプトのコンテキストでは一般的に使用できませんが、(疑似)人間のオペレーターと対話する場合にのみ使用できます。(疑似とはexpect、特定のオペレーターが人間以下である可能性があることを意味するのではなく、一般的に人間の行動を演じようとする他のキーストローク反復自動化ツールのようなもので動作させることができることを意味します)。

于 2012-08-23T19:05:34.863 に答える