削除されたディレクトリで終了する必要があるのはなぜですか?

削除されたディレクトリで終了する必要があるのはなぜですか?

私のサーバーには、次のディレクトリ構造があります。

/myproject/code

私は通常、サーバーにSSHで接続し、そのディレクトリに「待機」します。

root@machine:/myproject/code#

新しいバージョンのコードを配布すると、コードディレクトリが削除され、次の内容が残ります。

root@machine:/myproject/code# ./run
-bash: ./run: No such file or directory

私が見つけた唯一の解決策は、CDを取り出して元に戻すことです。

root@machine:/myproject/code# cd ../code
root@machine:/myproject/code# ./run
Running...

これを避けることはできますか?これは少し奇妙な行動です。なぜこれが起こるのかについて良い説明があれば、とても感謝します。

答え1

私にとって「cd../code」は愚かです。なぜこれが本当ではないのか聞きたいです。

ファイルとディレクトリは本質的にファイルシステムアノード、名前ではなく - これはファイルシステムの種類に固有の実装の詳細かもしれませんが、すべての外部システムに対応するので、ここでは使い続けます。

いつ新しいディレクトリがcode作成されたら、そのディレクトリを持つ新しいinodeに関連付けられます。以前に削除されたファイルとディレクトリの履歴はアーカイブされないため、システムは一度占有されたinodeを調べることができず、内容を再度同じにするために再配置することもできません。これらのシステムはすぐに機能しなくなり、いかなる場合でも再びそこに戻るという保証はありません。これはやや望ましくない。これは、ディレクトリが作成されると、誤って(現在使用されていない)inodeが他の必要な場所に終わる可能性があることを意味するためです。

この最後の可能性が存在するか、現在の作業ディレクトリに現在割り当てられている削除済みディレクトリのinodeが追跡され、その期間に何も割り当てられていないかどうかはわかりません。

答え2

あなたの殻いいえ次のコマンドを実行する前に、cd前のコマンドが実行されたパスで毎回タスクが実行されます。

現在のディレクトリを削除して同じ名前のディレクトリを作成しましたが、これは同じディレクトリではなく同じ名前/パスを持つディレクトリにすぎません。

ローカルファイルシステムのディレクトリが削除されると、NautilusやWindowsエクスプローラなどのファイルブラウザは、ディレクトリツリーを「上」に移動します。しかし、ネットワークファイルシステムの場合、必ずしもそうではありません。この場合、時には削除が目立たずに再び表示され、新しいディレクトリに残ることがあります。

シェルは、cd次のコマンドを実行する前に現在のディレクトリに移動できますが、これを行う項目はありません(またはこれを行うように構成できます)。

答え3

ほとんどのUNIXファミリシステムでは、プロセスの「現在のディレクトリ」は、そのディレクトリを指すファイル記述子としてカーネルに格納されます。カーネルは実際には現在のディレクトリへのパスを保存しません。この情報はシェルによって追跡されます。

ファイルシステムオブジェクト(ファイルまたはディレクトリ)は、すべてのファイルシステムリンクが消えた場合にのみ永久に破壊されます。そしてオブジェクトを指すファイル記述子はありません。

そのため、ディレクトリを削除してもそのディレクトリを現在の作業ディレクトリとして保持するプロセスがまだある場合、そのプロセスはディレクトリがcwd実際に削除されるのを防ぎます。ディレクトリ(親ディレクトリのエントリとすべての内容)を固定するファイルシステムリンクは消えますが、ディレクトリ自体はある種の「ゾンビ」として存在し続けます。同時に、以前のディレクトリと同じ場所にまったく新しいディレクトリを作成できます。これはまったく異なるファイルシステムオブジェクトですが、同じパスを共有します。

したがって、これを行うとcd ../code(または多くのシェルでcd .)実際にファイルシステム階層を探索し、新しい古いアドレスのディレクトリです。

例えば、ディレクトリを削除することは、家を強制的にゴミ箱に移動するのと同じです(以前のアドレスとの接続を解除する)。まだそこに住んでいる人がいる場合(自分の家として使う場合cwd)、家が撤去される前に去らなければなりません。その間、以前の住所に全く新しい家を建てることができます。

答え4

現在の作業ディレクトリーが照会したディレクトリー番号ではなく、inode 番号に基づいていることを確認してください。 bashを使用しているので、$ PWDを使用して同じ名前の新しいディレクトリに移動できます。

CD $PWD

これを説明するために、ダミー配布コマンドを作成しました。

set -x
cd ~/tmp
rm -rf code
mkdir code
echo echo hello from $* > code/run
chmod +x code/run

最初のデプロイを作成してコードに移動した後、ls -laiinodeを表示できるように内容を調べます。

ianh@abe:~/tmp$ ./,deploy first
++ cd /home/ianh/tmp
++ rm -rf code
++ mkdir code
++ echo echo hello from first
++ chmod +x code/run
ianh@abe:~/tmp$ cd code
ianh@abe:~/tmp/code$ ls -lai
total 12
22945913 drwxr-xr-x  2 ianh ianh 4096 Apr  9 23:12 .
22937618 drwxrwxr-x 14 ianh ianh 4096 Apr  9 23:12 ..
22939455 -rwxr-xr-x  1 ianh ianh   22 Apr  9 23:12 run

次に、2番目の展開を実行します。

ianh@abe:~/tmp/code$ ../,deploy 2nd
++ cd /home/ianh/tmp
++ rm -rf code
++ mkdir code
++ echo echo hello from 2nd
++ chmod +x code/run

ディレクトリの内容を確認しました...今、ディレクトリには何もありません!でも」。 「そして」..!ここで実行すると、「..」が存在しなくなるため、bashが「..」ディレクトリエントリを使用しないことがわかりますcd ..。私の考えでは、これが$ PWD処理の一部であるようです。一部の他の/古いシェルはcd ..この状況を処理できないため、まず絶対パスでcdする必要があります。

ianh@abe:~/tmp/code$ ls -lai
total 0

CDを$PWD挿入してもう一度やり直してください。

ianh@abe:~/tmp/code$ cd $PWD
ianh@abe:~/tmp/code$ ls -lai
total 12
22945914 drwxr-xr-x  2 ianh ianh 4096 Apr  9 23:12 .
22937618 drwxrwxr-x 14 ianh ianh 4096 Apr  9 23:12 ..
22939455 -rwxr-xr-x  1 ianh ianh   20 Apr  9 23:12 run
ianh@abe:~/tmp/code$ ./run
hello from 2nd

現在のディレクトリ(.)のinodeがどのように変更されるかを確認してください。

mv code code.$$上記のデプロイスクリプトと同様に、デプロイスクリプトが古いディレクトリを別の名前に移動した場合に./run機能します。しかし、cd $PWD使用するまで古いコードは新しいものではありません。

ianh@abe:~/tmp/code$ ./run
hello from 2nd
ianh@abe:~/tmp/code$ ../,deploy 3rd
++ cd /home/ianh/tmp
++ '[' -d code ']'
++ mv code code.9629
++ mkdir code
++ echo echo hello from 3rd
++ chmod +x code/run
ianh@abe:~/tmp/code$ ./run
hello from 2nd
ianh@abe:~/tmp/code$ cd $PWD
ianh@abe:~/tmp/code$ ./run
hello from 3rd

capistranoを使用して展開すると同じ問題が発生したため(現在の名前から現在のバージョンへのシンボリックリンクがあるため)、エイリアスを使用して本番/ステージング領域に移動し、RAIL_ENVを適切に設定しました。

alias cdp='export RAILS_ENV=production; echo RAILS_ENV=$RAILS_ENV ; cd /var/www/www.example.com/current'
alias cds='export RAILS_ENV=staging; echo RAILS_ENV=$RAILS_ENV ; cd /var/www/staging.example.com/current'

関連情報