web-dev-qa-db-ja.com

端末履歴をbashファイルからファイルに保存する方法は?

端末履歴をhist.txtというファイルに保存するbashスクリプトを作成しようとしています。 history > hist.txtの使用はbashスクリプトでは機能しないようですが、コマンドラインで実行すると正常に機能します。

どんなガイダンスも大歓迎です。

ありがとうジュディ

8
Judy

簡潔な答え

sourceまたは.を使用してスクリプトを実行します。

source ./script_name.sh

または

. ./script_name.sh

後者は、異なるシェル間でわずかに互換性があります。

ロングアンサー

この質問は重要なポイントを強調しています。つまり、シェルスクリプトは独自のコンテキストで実行されるということです。これが何を意味するかを確認するには、次のシェルスクリプトを検討してください。

#!/bin/bash

cd /
ls

これを実行すると、次のような出力が得られます。

bin  boot  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

ただし、スクリプトを実行した後、実行前のディレクトリにいることに気付くでしょう。スクリプト内のcd /は、実際にはセッションに影響を与えていません。スクリプトが実行されるために作成され、スクリプトが戻ると破棄されました。

sourceコマンドは「現在のシェルコンテキストのファイル名引数からコマンドを読み取って実行する」ため、その中のcdなどのコマンドは現在のセッションに影響します。上記のスクリプトをsourceに渡して実行する場合、実行後にルートディレクトリ内で終了することがわかります。

この場合、問題はhistoryコマンドが現在のシェルコンテキストの履歴を提供することです。 sourceを使用せずにスクリプトを実行するシェルコンテキストには履歴がないため、出力ファイルには何も書き込まれません。 sourceを使用すると、正しいコンテキストで実行され、期待どおりに機能します。

NB:sourceはシェルではなくプログラムです本質的に-Bashでは、source.と同義ですが、一部のシェルでは.は機能します-.より読みやすいので、この回答でsourceを使用しましたが、最大限の互換性を確保するには.を使用する必要があります。

11
p0llard

まず、履歴が既にファイルにあることに注意してください。 bashを実行している場合、その名前は通常~/.bash_historyです。具体的には、変数HISTFILEを設定したものです。別のファイルにコピーする場合は、cat "$HISTFILE" > hist.txtを実行するだけです

ここで、historyコマンドがbashシェルスクリプトで機能しない理由については、現在のシェルセッションの非対話型の子シェルでスクリプトが実行されるためです。子シェルは親のすべての環境を継承するわけではなく(設定された変数のすべてを継承するわけではありません)、エクスポートされた変数のみを継承します。説明のために、以下のスクリプトは変数$varの値をエコーし​​ます。

#!/bin/bash
echo "$var"

次に、$varを何かに設定して、スクリプトを実行します。

$ var="foo"
$ foo.sh
VAR: 

次に、最初に変数をエクスポートします。

$ var="foo"
$ export var
$ foo.sh
VAR: foo

ご覧のとおり、変数がエクスポートされると、子シェルで使用できます。

前述したように、履歴は変数$HISTFILENAMEが指すファイルに保存されます。これはデフォルトではエクスポートされないため、スクリプトの実行時には設定されません。

$ cat foo.sh
#!/bin/bash
echo "HISTFILE: $HISTFILE"
$ ./foo.sh
HISTFILE:
$ echo $HISTFILE
/home/terdon/.bash_history

上記の例でわかるように、変数HISTFILEは通常のシェルセッションで設定されていますが、スクリプトの実行時には空です。

したがって、履歴を取得するには、いくつかのオプションがあります。

  1. デフォルトのHISTFILE値は$HOME/.bash_historyです。変更していない場合は、スクリプトで次のコマンドを実行するだけです。

    cat "$HOME/.bash_history" > history
    
  2. $HISTFILE変数をスクリプトに渡し、catを渡すことができます。

    #!/bin/bash
    cat "$1" > history
    

    上記をfoo.shとして保存し、次のように実行します。

    ./foo.sh "$HISTORY"
    
  3. 変数がエクスポートされていることを確認してください。この行を~/.bash_profile(存在する場合)または~/.profile~/.bash_profileが存在しない場合)ファイルに追加します。

    export HISTFILE
    

    その後、ログアウトして再度ログインすると、期待どおりにスクリプトからhistory > hist.txtを実行できるはずです。これは、export VARが「子シェルで$ VARを使用可能にする」ことを意味するためです。実際的には、これは、HISTFILEの値が、スクリプトの実行に使用する非対話型シェルに継承されることを意味します。

    これで、HISTFILEが設定されますが、スクリプトを実行するシェルによって読み取られていません。したがって、それを機能させるには、最初にhistory -rで読む必要があります。スクリプト全体は次のようになります。

    $!/bin/bash
    history -r
    history > hist.txt
    

    または、スクリプトを実行する前に手動でエクスポートするだけです。

    $ export HISTFILE
    

    ただし、スクリプトではhistory -rが必要です。

  4. @ p0llard's answer で提案されているように、sourceできます。

10
terdon