ลบไฟล์ แต่เป็น symlink เท่านั้น


11

เป็นการดีที่ฉันต้องการคำสั่งเช่นนี้

rm --only-if-symlink link-to-file

เพราะฉันเขียนตัวเองหลายครั้งเกินไปการลบไฟล์โดยไม่ได้ตั้งใจแทนที่จะเป็น symlink ที่ชี้ไปที่ไฟล์ สิ่งนี้อาจไม่ดีโดยเฉพาะอย่างยิ่งเมื่อเกี่ยวข้องกับ sudo ตอนนี้ฉันทำแน่นอนls -alเพื่อให้แน่ใจว่ามันเป็น symlink จริง ๆ แต่มันก็มีความเสี่ยงต่อข้อผิดพลาดของผู้ปฏิบัติงาน (ไฟล์ที่มีชื่อคล้ายกันพิมพ์ผิด ฯลฯ ) และสภาพการแข่งขัน (ถ้ามีคนต้องการให้ฉันลบไฟล์ด้วยเหตุผลบางอย่าง) มีวิธีการตรวจสอบว่าไฟล์เป็น symlink และลบมันถ้ามันอยู่ในคำสั่งเดียว?


1
ฉันไม่คิดว่าสภาพการแข่งขันควรเป็นปัญหา ใครก็ตามที่จะสามารถลบ symlink และแทนที่ด้วยไฟล์จะต้องได้รับอนุญาตในการเขียนในไดเรกทอรีซึ่งหมายความว่าพวกเขาสามารถลบไฟล์ด้วยตนเอง
Nate Eldredge

คำตอบ:


19
 $ rm_if_link(){ [ ! -L "$1" ] || rm -v "$1"; }

 #test
 $ touch nonlink; ln -s link
 $ rm_if_link nonlink
 $ rm_if_link link
   removed 'link'     

4
แน่นอนว่าการลบ!และเปลี่ยน||เป็น&&
glenn jackman

5
@glennjackman ฉันทำให้มันเป็นนิสัยที่ชอบ||แบบฟอร์ม &&นำสิ่งต่าง ๆ ลงถ้าคุณอยู่ในset -eโหมด
PSkocik

@PSkocik นั้นมีความเสี่ยงโดยทั่วไปเนื่องจากไม่ได้แยกความแตกต่างระหว่างกรณีที่น่าสนใจ (ไฟล์มีอยู่และเป็น symlink) และเหตุผลอื่น ๆ สำหรับรหัสออกที่ไม่ใช่ศูนย์เช่นค่า unquote ที่ว่างเปล่า ( [ ! -L $1 ]) โดยใช้ตัวดำเนินการที่ไม่ถูกต้อง ( [ ! -l foo ]) หรือข้อผิดพลาดทางไวยากรณ์ ( [ ! -q foo || echo foo)
l0b0

2
@XiongChiamiov ปัญหาที่เกิดขึ้นrm_if_link(){ [ -L "$1" ] && rm -v "$1"; }ก็คือการรันมันบน nonlink ในset -e โหมดจะทำให้กระบวนการเชลล์ของคุณตาย คุณสามารถผนวก|| :แต่แล้วจะกลายเป็น IMHO แม้แต่น้อยที่ชัดเจนกว่า! ||รุ่นและจะป้องกันrmความล้มเหลวจากการฆ่าคุณในset -eซึ่งมีแนวโน้มที่ไม่พึงประสงค์ ! ||ค่อนข้างกระชับและชัดเจนและไม่ประสบปัญหาใด ๆ เหล่านี้
PSkocik

1
Nope ตัวเลือกอื่น ๆ : a) ใส่rmในการทดสอบของคุณ, b) ใช้จริงถ้า statement, c) อย่าไปใช้-eในเชลล์เชิงโต้ตอบ (และทดสอบสคริปต์ของคุณ!) หากคุณต้องการโต้แย้งเกี่ยวกับความสามารถในการอ่านใช้ifเพื่อทดสอบว่าลิงก์เป็นอะไรที่ค่อนข้างชัดเจนว่าเป็นผู้ชนะ
Boycott SE สำหรับ Monica Cellio

5

คุณสามารถใช้findและ-type lเงื่อนไขการทดสอบของมัน(ซึ่งการทดสอบเพื่อดูว่าวัตถุที่พบเป็นหมึกlหรือไม่)

ตัวอย่างเช่นหากคุณมีไฟล์ชื่อfooในไดเรกทอรีปัจจุบันคุณสามารถทำได้:

$ find . -type l -iname "foo" -delete

คุณอาจสามารถทำให้มันง่ายขึ้นด้วยเพียง:

$ find . -maxdepth 1 -type l -delete

ซึ่งจะลบ symlink ทั้งหมดในไดเรกทอรีปัจจุบัน

คำเตือน:

-deleteตัวเลือกในfindมันอันตรายจริงๆ ให้แน่ใจว่าได้วางไว้ที่ส่วนท้ายของคำสั่งการค้นหา หากคุณใส่ผิดที่มันจะลบทุกอย่างที่พบโดยไม่คำนึงว่าผลลัพธ์นั้นตรงกับเงื่อนไขของคุณหรือไม่

ตามที่แนะนำในความคิดเห็นตัวเลือกที่ปลอดภัยอาจจะใช้findและrm -i(ซึ่งบังคับให้คุณยืนยันการลบไฟล์) ในรูปแบบ:

$ $ find . -type l -iname "foo" | xargs rm -i

โดยส่วนตัวฉันใช้-exec trash {} \;เพื่อลบไฟล์ชั่วคราวเนื่องจากrmในอดีตฉันเคยถูกเผาเช่นเดียวกับตัวคุณ Double ใช้สำหรับการวาง-deleteธงผิดตำแหน่ง

http://slackermedia.ml/trashy


1
แทนที่จะลบ - คุณสามารถพิมพ์มันและส่งต่อไปที่ xargs: find . -type l -iname "foo" | xargs rm -i ปลอดภัยกว่า
Boban P.

1
ฉัน ชอบ@BobanP. การใช้rm -iเพื่อความปลอดภัยแน่นอน
Klaatu von Schlacker

3
"นี่จะลบ symlink ทั้งหมดในไดเรกทอรีปัจจุบัน" ... และจุดใด ๆ ข้างล่างนี้
โจเซฟอา

1
เป็น @JosephR กล่าวว่ามันจะไปตลอดทางตามถนน เพิ่ม -maxdepth 1 ในการค้นหา
Boban P.

1
ยังคงแบ่งในชื่อไฟล์ที่มีช่องว่าง ขอแนะนำให้ใช้-print0สำหรับfindและสำหรับ-0 xargs
Wildcard

4
zsh -c 'rm foo(@)'

@เป็นรอบคัดเลือก glob ; รูปแบบที่foo(@)ตรงกับสิ่งที่fooตรง แต่เฉพาะการเชื่อมโยงสัญลักษณ์

foo(-@)จะจับคู่ลิงก์สัญลักษณ์ที่ใช้งานไม่ได้เท่านั้น foo(@,L0)จะจับคู่ลิงก์สัญลักษณ์และไฟล์ว่างเปล่าเท่านั้น

แน่นอนถ้าคุณกำลังใช้ zsh rm foo(@)ในสถานที่แรกที่คุณเพียงแค่ต้องประเภท คุณไม่จำเป็นที่จะต้องดูแลไม่ให้กดก่อนพิมพ์Enter(@)


1
Zsh ฟังดูมีพลังมากขึ้นเมื่อฉันเห็นคำตอบเช่นนี้
Jeff Schaller
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.