私はシンボリックリンクを解決せずにファイルの絶対パスを返すコマンドを探しています。一般に、realpath
これはうまく行われました。
$ mkdir /tmp/test; cd /tmp/test
$ mkdir foo
$ ln -s foo bar
$ realpath -se bar # good, this does not resolve the symlink
/tmp/test/bar
また、シンボルでリンクされたディレクトリ内のファイルにも機能します。
$ touch foo/file
$ realpath -se bar/file # good, this does not resolve the symlink
/tmp/test/bar/file
ただし、県取締役の場合はいシンボリックリンクディレクトリ
$ cd bar
$ pwd
/tmp/test/bar
$ realpath -se file # this fails, returning the target
/tmp/test/foo/file
$ realpath -se . # this also fails, returning the target
/tmp/test/foo
$ realpath -se /tmp/test/bar/file # yet this works
/tmp/test/bar/file
$ realpath -se /tmp/test/bar # and this works
/tmp/test/bar
なぜrealpath
これが起こるのですか? (バグですか?)シンボリックリンクを決して解決できない方法がありますかrealpath
、それとも別の方法を使用する必要がありますか?
答え1
プロセスの現在の作業ディレクトリ(CWD)は、オペレーティングシステムレベルの以前のプロセスから継承または使用できますchdir(2)
。オペレーティングシステム(ここでは「カーネル」を意味します)はもちろん、最終ディレクトリを決定するために常にすべてのシンボリックリンクを確認してください。結果は(ディレクトリへの)シンボリックリンクではなくディレクトリでなければなりません。たとえば、chdir(2)
解決する必要があるシンボリックリンクが多すぎると、古いシステムコール()がエラーを返す可能性があります。ELOOP
したがって、オペレーティングシステムの観点からは、プロセスのディレクトリではないCWDディレクトリはありません。オペレーティングシステムはどこにもシンボリックリンクなしで常にそれを実際のパスとしてチェックします。
シェルが完了すると、cd /tmp/test/bar
CWDパスはオペレーティングシステムによって確認されます/tmp/test/foo
。たとえば、Linuxシステムでは、ls -l /proc/$$/cwd
カーネルに表示される確認済みのパスへのリンクが表示されます/tmp/test/foo
。
bar
シェルがまだプロンプトに表示されるという事実は、シェルが覚えているからです。CD以前に完了したコマンドです。この動作はシェルの種類によって異なります。ここにbashがあるとします。したがって、これは組み込まれていますがpwd
(外部コマンドではありません/bin/pwd
)、$PWD
変数とその使用は$PS1
現在のディレクトリに対してユーザーに「嘘」を付けます。
もちろん、シェルで実行または実行されるすべてのプロセスは継承されrealpath
ます。/bin/pwd
実際CWDは/tmp/test/foo
バグではなく、realpath
これに関する具体的な情報はありませんbar
。
Kusalanandaが提案したように、潜在的に厄介なアプローチは、何らかの方法で変数を再利用し、$PWD
変数が絶対的でない場合は引数の前に追加することです。realpath
ここに例があります。悪用する方法があるかどうかはわかりません。たとえば、以下の関数は対処しますが、$PWD
変数自体はbash 4.4.12(Debian 9)ではうまく機能しませんが、パスに改行がある場合はbash 5.0.3(Debian 10)ではうまく機能します。どこかに改行文字がある場合に便利な-z
オプションを追加する必要がありますrealpath
が、この簡単な例ではオプションの完全な解析を再実装しません。
myrealpathnofollowsym () {
for p in "$@"; do
if ! printf '%s' "$p" | grep -q -- '^/'; then
realpath -se "$PWD/$p"
else
realpath -se "$p"
fi
done
}