Bagaimana cara seseorang mengubah symlink ke direktori di busybox?

18

Saya mencoba (sedekat mungkin) secara atom mengubah symlink. Saya sudah mencoba:

ln -sf other_dir existing_symlink

Itu baru saja meletakkan symlink baru di direktori yang menunjuk existing_symlink.

ln -sf other_dir new_symlink
mv -f new_symlink existing_symlink

Itu melakukan hal yang sama: itu memindahkan symlink ke direktori.

cp -s other_dir existing_symlink

Itu menolak karena itu adalah direktori.

Saya pernah membaca bahwa mv -Tini dibuat untuk ini, tetapi busybox tidak memiliki -Tbenderanya.

Shawn J. Goff
sumber

Jawaban:

1

Saya tidak melihat bagaimana Anda bisa mendapatkan operasi atom. Halaman manual untuk symlink(2)mengatakan itu memberi EEXISTjika target sudah ada. Jika kernel tidak mendukung operasi atom, batasan userland Anda tidak relevan.

Saya juga tidak melihat bagaimana mv -Tmembantu, bahkan jika Anda memilikinya. Cobalah di kotak Linux biasa, satu dengan GNU mv:

$ mkdir a b
$ ln -s a z
$ mv -T b z
mv: cannot overwrite non-directory `z' with directory `b'

Saya pikir Anda harus melakukan ini dalam dua langkah: menghapus symlink lama dan membuatnya kembali.

Warren Young
sumber
1
Memang, sayangnya tidak ada cara Anda dapat memodifikasi simbolik secara atom. Yang terbaik yang dapat Anda lakukan adalah menghapus tautan lama dan membuat yang baru. GNU coreutils memiliki opsi untuk melakukan ini dengan satu perintah ( ln -snf), tetapi masih ada dua panggilan sistem di bawah tenda.
Gilles 'SO- stop being evil'
43

Ini dapat memang dilakukan atom dengan rename(2), dengan terlebih dahulu menciptakan symlink baru di bawah nama sementara dan kemudian bersih Timpa symlink lama dalam satu pergi. Seperti yang dinyatakan halaman manual :

Jika jalur baru merujuk ke tautan simbolis, tautan tersebut akan ditimpa.

Dalam shell, Anda akan melakukan ini dengan cara mv -Tsebagai berikut:

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

Anda dapat straceperintah terakhir itu untuk memastikan memang menggunakan di rename(2)bawah kap:

$ 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

Perhatikan bahwa di atas, keduanya mv -Tdan straceLinux-spesifik.

Di FreeBSD, gunakan secara mv -hbergantian.

Arto Bendiken
sumber
1
Sangat bagus! Mungkin bermanfaat untuk mengatakan bahwa pada akhirnya Anda memiliki tautan dari z ke b!
Vincenzo Pii
Untuk solusi OS-independen gunakan bahasa scripting yang mampu menggunakan renamesyscall secara langsung, bukan mv -hatau mv -T. Misalnya dengan Perl:perl -e 'rename "z.new", "z" or die $!'
Slaven Rezic
8

Mengambil di mana Arto tinggalkan di sini, ini sepenuhnya mungkin, bahkan tanpa mv -T, Anda hanya perlu membuat symlink baru dengan nama yang sama dengan direktori target dan mvitu ke dalam direktori induk dari target Anda:

mkdir -p tmp/real_dir1 tmp/real_dir2
touch tmp/real_dir1/a tmp/real_dir2/a
# start with ./target_dir pointing to tmp/real_dir1
ln -s tmp/real_dir1 target_dir
# create a symlink named target_dir in tmp, pointing to real_dir2
ln -sf tmp/real_dir2 tmp/target_dir
# atomically mv it into ./ replacing ./target_dir
mv tmp/target_dir ./

Contoh kode diambil melalui ( http://axialcorps.wordpress.com/2013/07/03/atomically-replacing-files-and-directories/ )

mssaxm
sumber
3

Sudahkah Anda mencoba ln -snf?

Opsi -nmenimpa tujuan daripada menulis di bawahnya ketika tujuan adalah tautan simbolis ke direktori.

Bersulang

sokai
sumber
3
ln -snfbukan atomik: itu membatalkan tautan tujuan, lalu membuat symlink yang diinginkan.
Gilles 'SO- stop being evil'
2
Mengingat bahwa OP tertarik untuk mendapatkan "sedekat mungkin [e]" dengan perubahan symlink secara atom, ini adalah jawaban yang masuk akal. Jika ada yang lebih baik yang bisa lebih dekat (atau menjadi) atom, itu bisa diterima. Saya tidak berpikir ada kebutuhan untuk downvote.
Wilco