web-dev-qa-db-ja.com

シンボリックリンクが作成された後に、シンボリックリンクが指すものを変更できますか?

オペレーティングシステムは、古いものをリンク解除して新しいものを作成する以外に、シンボリックリンク(symlink)によって参照されるパス名を変更するメカニズム(コマンドラインプログラムではなくシステムコール)を提供しますか?

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

何かありますか?

(答えは「いいえ」になると思っています。)


否定を証明するのは難しいので、質問を再編成しましょう。

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

117

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

$ 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オプションを使用すると、lnunlink()の前にsymlink()へのシステムコールを実行します_。以下に、Linuxボックスでの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:以下は2016年頃のunix.stackexchange.comの Arto Bendikenの回答 からコピーされています。

このcanは、最初に一時的な名前で新しいシンボリックリンクを作成し、次に古いシンボリックリンクを一度にきれいに上書きすることにより、rename(2)でアトミックに実行されます。 manページ のように:

newpathがシンボリックリンクを参照している場合、リンクは上書きされます。

シェルでは、次のように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を交互に使用します。

編集者のメモ:これは、キャピストラーノがこれまで何年もやってきた方法です。 このプルリクエスト を参照してください。

100
Pascal Thivent

はい、できます!

$ ln -sfn source_file_or_directory_name softlink_name
156
Taai

古いシンボリックリンクを明示的にリンク解除する必要はありません。あなたはこれを行うことができます:

ln -s newtarget temp
mv temp mylink

(または同等のシンボリックリンクを使用して呼び出しを変更します)。名前の変更はアトミックであるため、これは明示的にリンク解除するよりも優れています。したがって、リンクは常に古いターゲットまたは新しいターゲットのいずれかを指していることが保証されます。ただし、これは元のiノードを再利用しません。

一部のファイルシステムでは、シンボリックリンクのターゲットが十分に短い場合、iノード自体に(ブロックリストの代わりに)保存されます。これは、作成時に決定されます。

実際の所有者とグループが重要でないという主張に関して、Linuxの symlink(7) は、重要な場合があると述べています。

既存のシンボリックリンクの所有者とグループは、lchown(2)を使用して変更できます。シンボリックリンクの所有権が重要になるのは、スティッキービットが設定されているディレクトリでリンクが削除または名前変更されるときだけです(stat(2)を参照)。

シンボリックリンクの最終アクセスおよび最終変更のタイムスタンプは、utimensat(2)またはlutimes(3)を使用して変更できます。

Linuxでは、シンボリックリンクのアクセス許可はどの操作でも使用されません。アクセス許可は常に0777(すべてのユーザーカテゴリに対して読み取り、書き込み、実行)であり、変更できません。

12
mark4o

上記の正しい答えに対する警告:

-f/--forceメソッドを使用すると、ソースとターゲットを混同した場合にファイルを失うリスクがあります。

mbucher@server2:~/test$ ls -la
total 11448
drwxr-xr-x  2 mbucher www-data    4096 May 25 15:27 .
drwxr-xr-x 18 mbucher www-data    4096 May 25 15:13 ..
-rw-r--r--  1 mbucher www-data 4109466 May 25 15:26 data.tar.gz
-rw-r--r--  1 mbucher www-data 7582480 May 25 15:27 otherdata.tar.gz
lrwxrwxrwx  1 mbucher www-data      11 May 25 15:26 thesymlink -> data.tar.gz
mbucher@server2:~/test$ 
mbucher@server2:~/test$ ln -s -f thesymlink otherdata.tar.gz 
mbucher@server2:~/test$ 
mbucher@server2:~/test$ ls -la
total 4028
drwxr-xr-x  2 mbucher www-data    4096 May 25 15:28 .
drwxr-xr-x 18 mbucher www-data    4096 May 25 15:13 ..
-rw-r--r--  1 mbucher www-data 4109466 May 25 15:26 data.tar.gz
lrwxrwxrwx  1 mbucher www-data      10 May 25 15:28 otherdata.tar.gz -> thesymlink
lrwxrwxrwx  1 mbucher www-data      11 May 25 15:26 thesymlink -> data.tar.gz

もちろんこれは意図されていますが、通常は間違いが発生します。したがって、シンボリックリンクの削除と再構築はもう少し手間がかかりますが、ちょっとした節約にもなります。

mbucher@server2:~/test$ rm thesymlink && ln -s thesymlink otherdata.tar.gz 
ln: creating symbolic link `otherdata.tar.gz': File exists

少なくとも私のファイルを保持します。

2
Markus Bucher

とにかくそれをリンク解除して新しいものを作成しても同じことをしませんか?

1
matt b

技術的には、既存のシンボリックリンクを編集するための組み込みコマンドはありません。いくつかの短いコマンドで簡単に実現できます。

ここに少しありますbash/zsh function私は既存のシンボリックリンクを更新するために書きました:

# -----------------------------------------
# Edit an existing symbolic link
#
# @1 = Name of symbolic link to edit
# @2 = Full destination path to update existing symlink with 
# -----------------------------------------
function edit-symlink () {
    if [ -z "$1" ]; then
        echo "Name of symbolic link you would like to edit:"
        read LINK
    else
        LINK="$1"
    fi
    LINKTMP="$LINK-tmp"
    if [ -z "$2" ]; then
        echo "Full destination path to update existing symlink with:"
        read DEST
    else
        DEST="$2"
    fi
    ln -s $DEST $LINKTMP
    rm $LINK
    mv $LINKTMP $LINK
    printf "Updated $LINK to point to new destination -> $DEST"
}
0
blizzrdof77

念のため:真夜中の司令官(mc)でシンボリックリンクを編集する方法があります。メニューコマンドは次のとおりです(私のmcインターフェースではフランス語で):

Fichier / Éditer le lien symbolique

次のように翻訳できます:

File / Edit symbolic link

ショートカットはC-x C-sです

内部でln --forceコマンドを使用しているのかもしれませんが、わかりません。

今、私は一度にたくさんのシンボリックリンクを編集する方法を見つけようとしています(それが私がここに到着した方法です)。

0
Pierre