web-dev-qa-db-ja.com

削除したディレクトリからcdする必要があるのはなぜですか?

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

/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...

これを回避できますか?これは少し奇妙な動作です。なぜこれが起こるのかについての素晴らしい説明があれば、私はそれを感謝します。

19

私にとって「cd ../code」は何もしません。なぜそうならないのか聞いてとても興味があります。

ファイルとディレクトリは基本的に filesystem inodes であり、名前ではありません-これはおそらくファイルシステムタイプに固有の実装の詳細ですが、すべてのextシステムに当てはまるため、ここで固執します。

newディレクトリcodeが作成されると、新しいiノードに関連付けられます。以前に削除されたファイルとディレクトリの記録は保持されていないため、システムがどのiノードが占有していたものをチェックし、おそらく同じになるようにシャッフルすることができません。そのようなシステムはすぐに機能しなくなり、いずれにしても、再びそこに戻ることはおそらく保証されません-これは、ディレクトリが作成された場合に誤って別の場所に移動する可能性があることを意味するため、一種の望ましくないことになりますこれは(現在未使用の)iノードを取ります。

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

26
goldilocks

シェルしないでください毎回、最後のコマンドの実行中にあったパスにcdを実行してから、次のコマンドを実行します。

現在のディレクトリを削除し、同じ名前のディレクトリを作成しました。これは同じディレクトリではなく、同じ名前/パスを持つ何かだけです。

NautilusやWindows Explorerなどのファイルブラウザは、ローカルファイルシステムでディレクトリが削除されると、通常、ディレクトリツリーを「上に移動」します。ただし、これはネットワーク化されたファイルシステムには常に当てはまるとは限りません。その場合、削除が認識されず、再表示によって新しいディレクトリに移動することがあります。

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

14
Anthon

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

ファイルシステムオブジェクト(ファイルorディレクトリ)は、そのファイルシステムへのリンクがすべて削除された場合にのみ破棄されますandそのオブジェクトを指すファイル記述子がない場合。

そのため、現在の作業ディレクトリとして保持しているプロセスがまだある間にディレクトリが削除された場合、プロセスのcwdは、ディレクトリが本当に削除されないようにします。ディレクトリ(親ディレクトリのエントリとそのすべてのコンテンツ)を固定するファイルシステムリンクはなくなりますが、ディレクトリ自体は一種の「ゾンビ」として存在し続けます。一方、完全に異なるファイルシステムオブジェクトであるが同じパスを共有する、古いディレクトリと同じ場所に新しいディレクトリを作成できます。

したがって、cd ../code(または、多くのシェルではcd .)、実際にはファイルシステム階層をたどって、古いアドレスにあるnewディレクトリに移動しています。

同様に、ディレクトリを削除することは、強制的に家をゴミ捨て場に移動することと同じです(以前のアドレスとの関係を断ち切る)。 (cwdとして使用して)そこにまだ誰かが住んでいた場合、家が破壊される前に彼らは去らなければなりません。その間に、古い住所に新しい家を建てることができます。

4
nneonneo

自己完結型の回答ではありませんが、コメントのマージンが小さすぎて収容できないという追加のポイントがあります。

関連するファイルシステムのディレクトリが単なるパスではないという考えをよく理解するには、別のプロセスの現在の作業ディレクトリを移動してみてください。1つのシェルで、インタラクティブPythonセッションを開始します。

$ python
>> import os
>> os.getcwd()
'/home/you/hocus'

次に、別のシェルに移動して、そのディレクトリを移動します。

$ cd /home/you
$ mv hocus pocus

元に戻す:

 $ python 
 >> import os 
 >> os.getcwd()
 '/ home/you/hocus' 
>> os.getcwd()
 '/ home/you/pocus'
0
Evgeni Sergeev

現在の作業ディレクトリの確認ISそこに到達するために調べたものではなく、iノード番号に基づいています。bashを使用しているため、$ PWDを次のように使用して、新しいディレクトリにcdできます。同じ名前:

cd $ PWD

説明のために、ダミーのデプロイコマンドを作成しました。

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

最初のデプロイメントを作成し、cdでコーディングしてから、ls -laiで内容をチェックして、iノードを確認できるようにします。

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

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

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

$PWDにCdして、もう一度お試しください:

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

現在のディレクトリ(。)のiノードがどのように変更されたかに注意してください。

デプロイスクリプトが古いディレクトリを他の名前に移動した場合、たとえば、上記のデプロイスクリプトのmv code code.$$の場合、./runは機能しますbutcd $PWDを使用するまで、新しいコードではなくoldコードを実行します。

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を使用してデプロイすると同じ問題が発生します(現在の名前から現在のリリースへのシンボリックリンクがあります)。したがって、エイリアスを使用して本番/ステージング領域にcdし、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'
0
iheggie

私が想定しているのは、パスがディレクトリを識別するものであるということです。

何かへの道はそこに到達する方法であり、それ自体ではありません。あなたのベッドへの道はあなたの部屋を通るかもしれませんが、あなたがベッドに入ると、誰かがそれを手に取って外に運ぶと、あなたはもはやあなたの部屋にはいません。

0
psusi

@Anthonは理由をクリアしました、なぜそれが起こるのか
解決策として、例としてaliasを使用できます。

alias 1234='PROJECT=`pwd`; cd $PROJECT ; ./run'

bashのエイリアスは〜/ .bashrcに保持されます

0
MolbOrg