web-dev-qa-db-ja.com

Bashには実行可能ファイルのキャッシュがありますか?

Ubuntu14.10コンピューターでC++プログラムを書いていました。これはクライアント/サーバープログラムであるため、3つのターミナルエミュレーターを開いています。1つはコードの記述とコンパイル用、もう1つはクライアントテスト用、最後の1つはサーバーテスト用です。しばらくして、コードにバグがあると思いました。私はそれを追跡するのに1時間以上失いました、そしてそれはディレクトリから出てそしてそれを再び入ることは全体の問題を解決したことがわかりました。正確には、これらは私が実行したコマンドでした。

some_directory$ ./client
some_directory$ cd ..
$ cd some_directory
some_directory$ ./client

何も変更せずに、また再コンパイルせずに、2回の実行で異なる結果が得られました。私が考えることができる唯一のことは、古いバージョンのファイルを保存するある種のキャッシュですが、そのような機能については聞いたことがありません。説明とその解決方法(ディレクトリを終了せずに自動的に更新する)はありますか?

5
akrasuski1

Bashはそれほど凝ったことはしないと思います(パスなしで指定された実行可能ファイルへのパスをキャッシュしますが、パスを指定しているため、ここでは適用されません)

あなたがいたディレクトリが移動またはマウントされたように聞こえます。ソフトウェアを構築する場合、ディレクトリの移動が発生する可能性が高くなります。

ディレクトリ移動の場合

ターミナル1でのディレクトリ移動の動作を再現する例

cd /tmp
mkdir dir1
cd dir1
touch exampleFile

次に、ターミナル2で。

cd /tmp
mv dir1 dir2
mkdir dir1
cd dir1

両方のシェルは「dir1」という名前のディレクトリにあるように表示されますが、リストには異なる内容が表示されます。 terminal2が「exampleFile」というファイルを作成する場合、両方のシェルは「dir1」に「exampleFile」を表示しますが、それらは異なるファイルです。これは、ターミナル1のシェルが実際にはdir2にあり、それを認識していないためです。ターミナル1のシェルは、cdを介して実際の「dir1」に到達できます。

cd .

これは奇妙に見えますが、パスを再解決します。

オーバーマウントケース

これは、シェル(または任意のプログラム)がディレクトリ内にあり、その上にファイルシステムがマウントされている場合に発生します。たとえば、ターミナル1:

mkdir /tmp/dir1
cd /tmp/dir1

ターミナル2:

mount /dev/whateverdev /tmp/dir1
cd /tmp/dir1

ターミナル1は、そのディレクトリ内の元のファイルシステムからのファイルを参照します。ターミナル2は、/ dev/whateverdevからのファイルを参照します。

回避する方法

オーバーマウントの場合、これはほとんどの場合、実行していることやマシンの構成方法を認識しているだけです(たとえば、USBドライブが接続されているときにオートマウンターが実行されている場合)。

ディレクトリ移動の場合、これはビルドシステムにもう少し依存します。古い出力ディレクトリを移動してバックアップし、新しいビルド用に新しいディレクトリを作成するルールがある場合、この状況に頻繁に遭遇します。ビルドルールにトリックがないか確認してください。

もちろん、これは1回限りの意図しない事故であった可能性もあります(上記の最初の例で示したものと同様)。その場合、これが起こり得るという認識があなたを助けます。

3
John O'M.

一般的にhashおよびsync

hash-bashの組み込みコマンド

コマンドを実行するときの操作を高速化するために、bashシェルはそのパスハッシュに格納しますテーブル。各Shellインスタンスには独自のhash tableがあります。詳細については、man bashからの抜粋をお読みください。

名前がシェル関数でもbuiltinでもなく、スラッシュが含まれていない場合、bashPATHの各要素で、その名前の実行可能ファイルを含むディレクトリを検索します。
Bashハッシュテーブルを使用して、実行可能ファイルのフルパス名を記憶します(hashを参照)。下Shell BUILTIN COMMANDS以下)。 PATH内のディレクトリの完全検索は、コマンドがハッシュテーブルで見つからない場合にのみ実行されます。

リスト内のエントリ(コマンドclientなど)をhash clientに置き換えることができます。 hash -d clientを使用してリストからこのエントリを消去できます。 hash -rでリストを完全にリセットできます。

Sync-ディスク上のデータをメモリと同期します

syncコマンドは、メモリ内のすべてがディスクに書き込まれるようにします。

多くの場合、操作を高速化するために、Linuxはカーネルファイルシステムバッファーにデータを格納できます。つまり、低レベルのI/Oシステムコールを介して書き込みがスケジュールされているデータ [1]

一方、「ハードディスクはデフォルトで独自の揮発性書き込みキャッシュを使用して書き込みをバッファリングする場合があります。これにより、パフォーマンスが大幅に向上し、書き込みが失われる可能性があります」 [2]

syncは、メモリにバッファリングされたデータをディスクに書き込みます。これには、変更されたスーパーブロック、変更されたiノード、および遅延読み取りと書き込みが含まれます(ただし、これらに限定されません)。これはカーネルによって実装される必要があります。 syncプログラムは、 `sync 'システムコールを実行するだけです。 カーネルはデータをメモリに保持して、(比較的遅い)ディスクの読み取りと書き込みを回避します。これによりパフォーマンスは向上しますが、...

[興味がある場合は、 ここ またはinfo coreutils sync]を読み続けてください。

あなたの問題に固有

問題が上記の側面の1つに依存している場合は、1行だけで複数のコマンドを記述し、上矢印キーですばやく呼び出した後、次のように入力できます。

  • hash -d ./client; ./client
  • sync ; ./client
  • hash -d ./client ; sync ; ./client
  • (cd .. ; cd - ; ./client )、あなた自身の解決策。ここでは、サブシェルでクライアントを実行します。このサブシェルは、シェルで行ったすべての遺産を(変数として...)取り込みます。ただし、現在のシェルへの変更は返されません。

コンパイル手順やクライアントとサーバー間のダイヤル操作に関連する操作を完全に理解していないと、原因を見つけるのが難しい場合があります(シンボリックリンク、またはの待ち時間が長い場合もあります) NFSファイルシステム...)。この場合、試行錯誤によってオリジンを検索する必要があります。

2
Hastur