1. ホーム
  2. unix

[解決済み] シンボリックリンクを作成した後に、そのシンボリックリンクの指す先を変更することはできますか?

2022-07-21 15:09:54

質問

シンボリックリンク (symlink) によって参照されるパス名を変更するメカニズム (コマンドライン プログラムではなくシステム コール) を提供するオペレーティング システムはありますか。

POSIX 標準ではそうなっていません。 Solaris 10 はそうではありません。 MacOS X 10.5 (Leopard) はそうではありません。(AIX や HP-UX もそうでないと、私はかなり確信しています。この一覧から判断すると Linux システムコール のリストから判断すると、Linuxにもそのようなシステムコールはありません)。

何かあるのでしょうか?

(答えは"No"であると予想しています)。


否定を証明するのは難しいので、質問を整理してみましょう。

まだリストアップされていないいくつかの (Unix ライクな) オペレーティングシステムが、シンボリックリンクの値 (が返す文字列) を書き換えるシステムコールがないことを知っている場合。 readlink() によって返される文字列) の値を、古いシンボリックリンクを削除して新しいものを作成することなく書き換えるためのシステムコールがないことを知っているなら、答えにそれを、またはそれらを追加してください。

どのように解決するのですか?

AFAIK、いいえ、できません。削除して再作成する必要があります。 実際には、シンボリックリンクを上書きして、それによって参照されるパス名を更新することができます。

$ ln -s .bashrc test
$ ls -al test
lrwxrwxrwx 1 pascal pascal 7 2009-09-23 17:12 test -> .bashrc
$ ln -s .profile test
ln: creating symbolic link `test': File exists
$ ln -s -f .profile test
$ ls -al test
lrwxrwxrwx 1 pascal pascal 8 2009-09-23 17:12 test -> .profile

EDIT : コメントでOPが指摘しているように --force オプションを使うと ln へのシステムコールを実行します。 unlink() の前に symlink() . 以下、出力される strace の出力がそれを証明しています。

$ strace -o /tmp/output.txt ln -s -f .bash_aliases test
$ grep -C3 ^unlink /tmp/output.txt 
lstat64("test", {st_mode=S_IFLNK|0777, st_size=7, ...}) = 0
stat64(".bash_aliases", {st_mode=S_IFREG|0644, st_size=2043, ...}) = 0
symlink(".bash_aliases", "test")        = -1 EEXIST (File exists)
unlink("test")                          = 0
symlink(".bash_aliases", "test")        = 0
close(0)                                = 0
close(1)                                = 0

EDIT : 以下は、以下からのコピーです。 Arto Bendiken さんの回答 にある、2016年頃のunix.stackexchange.comの回答です。

これは でアトミックに行うことができます。 rename(2) を使うことで、アトミックに行うことができます。このように マンページ にはこう書かれています。

もし 新しいパス がシンボリックリンクを参照している場合、そのリンクは上書きされます。

シェルでこれを行うには mv -T を次のようにします。

$ mkdir a b
$ ln -s a z
$ ln -s b z.new
$ mv -T z.new z

あなたは strace を使っていることを確認するために、最後のコマンドは rename(2) を使用していることを確認します。

$ strace mv -T z.new z
lstat64("z.new", {st_mode=S_IFLNK|0777, st_size=1, ...}) = 0
lstat64("z", {st_mode=S_IFLNK|0777, st_size=1, ...}) = 0
rename("z.new", "z")                    = 0

上の例では mv -Tstrace は Linux 固有のものです。

FreeBSDでは mv -h を交互に使ってください。

編集部注 これはCapistranoが2.15以降ずっと行っている方法です。参照 このプルリクエスト .