Symlinkフォルダ内にある場合は、親の場所からファイルをコピーします。

Symlinkフォルダ内にある場合は、親の場所からファイルをコピーします。

/tmpparentCalledとに2つのフォルダを作成するとしますchildchildというファイルが含まれており、test-child.txtというparentファイルが含まれていますtest-parent.txt。さて、私はあなたparentのためのシンボリックリンクを作成しましょうchild。次に入ってからコピーしてみてchildください。 Bashの完了はうまく機能しますが、実際のファイルのコピーは失敗します。test-parent.txtparent

cd /tmp
pwd
/tmp
mkdir parent
mkdir child
touch child/test-child.txt
ls child/
test-child.txt
cd parent
ln -sf ../child .
touch test-parent.txt
cd child
cp ../test-parent.txt .
cp: cannot stat ‘../test-parent.txt’: No such file or directory 

なぜ? ?

そして私がそこにいる間、child私がこう言ったら--

pwd
/tmp/parent/child

答え1

シェルはユーザーの便宜のためにシンボリックリンクに従います。これは、ディレクトリへのシンボリックリンクであってcd foo && cd ..も、常に元のディレクトリに戻るのに良い効果があります。fooこれには2つの欠点があります。主な欠点は、他のプログラムではこの機能を実行しないことです。また、シンボリックディレクトリの追跡には独自の問題が発生します(シンボルリンクが変更された場合はどうなりますか?プロセスにシンボリックリンクを読み取る権限がない場合はどうなりますか?など)。

シェルはすべてのディレクトリの変更を追跡し、そこにどのように到達したかを覚えているため、これだけを実行できます。新しいプロセスが開始されると、この履歴情報は取得されません。後ろには、ルートディレクトリに到達するまでリンクに沿って現在のディレクトリを上に移動して..場所を見つけます。

シンボリックリンクを介してディレクトリに到達した場合は、次のコマンドを使用してシンボリックリンクのパスを印刷できます。pwd組み込みのシェルpwd -Pから別のプログラムを呼び出す場合は、..シンボリックリンクコンポーネントを含むパスを渡さないでください。プログラムがこれを異なって解釈するからです。代わりに、以下を呼び出して..コンポーネントを削除してくださいpwd -P

cp "$(cd .. && pwd -P && echo /)test-parent.txt" .

cdシェルセッションで前のコマンドで使用されたシンボリックリンクを忘れるには、次のようにします。

cd "$(pwd -P && echo /.)"

これは現在のディレクトリに変更されるため、シェルプロセスの現在のディレクトリは効果的に変更されませんが、シェルが追跡する現在のディレクトリのパスを変更して、シンボリックリンクされていないリンクにします。

1これは伝統的に通話が機能する方法ですgetcwd。一部のカーネルは現在のディレクトリを追跡しますが、以前のバージョンとの互換性の理由ではない場合(シンボリックリンクの微妙な場合もあるため)、シンボリックリンクは追跡しません。

答え2

cpこれは、シェルが同じリンクゲームを実行していないためです。あなたのシェルは現在の作業ディレクトリの間接参照として現在の作業ディレクトリへのリンクをたどっていますが、シェルが呼び出されたときにカーネルは話すべきではありません。代わりに、カーネルは現在の作業ディレクトリへの完全な絶対パスをcp生成します。cp作業ディレクトリ - したがって、リンクは.シェルのリンクとは.異なります.

現在の作業ディレクトリの絶対パスを簡単に確認でき、cd -P .他のディレクトリにも同様に適用されますcd -P -- /any/other/directory少なくとものような印刷のための絶対パスでpwdあり、多くのシェルでは絶対パスに変更されることもあります。.pwd -P$PWD(同じ方法でcd -P .

たとえば、

cd /tmp
mkdir -p parent child
cd parent
ln -s ../child child
touch ./child/somefile
cd -L child                  ###the default
printf %s\\n "$PWD"/*
cd -P .
printf %s\\n "$PWD"/*

出力

/tmp/parent/child/somefile
/tmp/child/somefile

関連情報