หนึ่งอะตอมจะเปลี่ยน symlink เป็นไดเรกทอรีใน busybox ได้อย่างไร?


18

ฉันพยายาม (ใกล้เคียงที่สุด) อาจเปลี่ยน symlink ฉันได้พยายาม:

ln -sf other_dir existing_symlink

เพียงใส่ symlink ใหม่ในไดเรกทอรีที่มีอยู่แล้ว

ln -sf other_dir new_symlink
mv -f new_symlink existing_symlink

นั่นทำสิ่งเดียวกัน: มันย้าย symlink ไปยังไดเรกทอรี

cp -s other_dir existing_symlink

มันปฏิเสธเพราะมันเป็นไดเรกทอรี

ฉันอ่านแล้วว่าmv -Tทำมาเพื่อสิ่งนี้ แต่ busybox ไม่มีการ-Tตั้งค่าสถานะ

คำตอบ:


1

ฉันไม่เห็นวิธีที่คุณสามารถรับการทำงานของอะตอม man page สำหรับsymlink(2)บอกว่ามันให้EEXISTถ้าเป้าหมายมีอยู่แล้ว หากเคอร์เนลไม่รองรับการทำงานแบบปรมาณูข้อ จำกัด userland ของคุณจะไม่เกี่ยวข้อง

ฉันยังไม่เห็นวิธีที่mv -Tช่วยแม้ว่าคุณจะมีมัน ลองใช้บนกล่อง Linux ปกติหนึ่งรุ่นด้วย GNU mv:

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

ฉันคิดว่าคุณจะต้องทำเช่นนี้ในสองขั้นตอน: ลบ symlink เก่าและสร้างใหม่


1
ที่จริงแล้วไม่มีวิธีที่คุณสามารถปรับเปลี่ยนสัญลักษณ์แบบอะตอมได้ สิ่งที่ดีที่สุดที่คุณสามารถทำได้คือลบลิงค์เก่าและสร้างใหม่ coreutils ของ GNU มีตัวเลือกในการทำสิ่งนี้ด้วยคำสั่งเดียว ( ln -snf) แต่ยังคงมีการเรียกระบบสองระบบภายใต้ประทุน
Gilles 'หยุดความชั่วร้าย'

43

วิธีนี้สามารถทำได้ด้วยการใช้อะตอมrename(2)โดยการสร้าง symlink ใหม่ภายใต้ชื่อชั่วคราวก่อนแล้วจึงทำการเขียนทับ symlink เก่าในครั้งเดียว ดังที่man pageระบุ:

หาก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 -Tและstraceเฉพาะ Linux

บน FreeBSD ให้ใช้mv -hสลับกัน


1
ดีมาก! มันอาจจะมีประโยชน์ที่จะบอกว่าในตอนท้ายคุณมีลิงก์จาก z ถึง b!
Vincenzo Pii

เพื่อแก้ปัญหาระบบปฏิบัติการอิสระใช้ภาษาสคริปต์ซึ่งเป็นความสามารถในการที่จะใช้renamesyscall โดยตรงแทนหรือmv -h mv -Tตัวอย่างเช่นกับ Perl:perl -e 'rename "z.new", "z" or die $!'
Slaven Rezic

8

การเลือกที่ที่อาร์โต้จะออกจากที่นี่เป็นไปได้โดยสิ้นเชิงแม้ว่าmv -Tคุณจะต้องสร้าง symlink ใหม่ด้วยชื่อเดียวกับไดเรกทอรีเป้าหมายและmvลงในไดเรกทอรีหลักของเป้าหมายของคุณ:

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 ./

ตัวอย่างโค้ดที่ถ่ายผ่าน ( http://axialcorps.wordpress.com/2013/07/03/atomically-replacing-files-and-directories/ )


3

คุณเคยลองln -snfไหม

ตัวเลือก-nจะเขียนทับจุดหมายปลายทางแทนการเขียนภายใต้เมื่อปลายทางเป็นลิงค์สัญลักษณ์ไปยังไดเรกทอรี

ไชโย


3
ln -snfไม่ใช่อะตอมมิก: มันจะยกเลิกการเชื่อมโยงปลายทางจากนั้นสร้าง symlink ที่ต้องการ
Gilles 'หยุดความชั่วร้าย' ใน

2
เนื่องจาก OP มีความสนใจในการ "ใกล้เคียงกับ possib [e]" เพื่อเปลี่ยน symlink แบบอะตอมนี่คือคำตอบที่สมเหตุสมผลอย่างสมบูรณ์แบบ หากมีสิ่งที่ดีกว่าที่สามารถเข้าใกล้ (หรือ) อะตอมก็สามารถยอมรับได้ ฉันไม่คิดว่ามันจำเป็นที่จะต้องลงคะแนน
Wilco
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.