การอ้างชื่อไฟล์มีความปลอดภัยเพียงพอหรือไม่ในการใช้งาน `xargs sudo rm -rf`?


10

ฉันเขียนสคริปต์ที่ลบทั้งหมดยกเว้นไฟล์สองไฟล์สุดท้ายในโฟลเดอร์:

#!/bin/bash
ls -1 --quoting-style=shell-always /path/to/some/folder \
    | head -n -2 \
    | xargs printf -- "'/path/to/some/folder/%s'\n" \
    | xargs sudo rm -rf

สคริปต์นี้จะถูกเรียกใช้เป็นงาน cron ทุกวัน

เหตุผลมีดังนี้:

  1. รับรายการไฟล์ทั้งหมดโดยใช้ls -1(เพื่อให้ได้หนึ่งไฟล์ต่อบรรทัด);

  2. นำสองคนสุดท้ายจากรายการใช้head -n -2;

  3. ตั้งแต่lsพิมพ์พา ธ ที่สัมพันธ์กันให้ใช้xargs printfสิ่งต่าง ๆ เพื่อผนวกเส้นทางโฟลเดอร์และทำให้เป็นพา ธ สัมบูรณ์

  4. ส่งพวกเขาไปใช้sudo rm -rfxargs

ทุกคนสามารถเข้าถึงโฟลเดอร์นี้เพื่อให้ทุกคนสามารถสร้างและลบไฟล์ใด ๆ ในโฟลเดอร์นี้

ปัญหาคือ: sudo rm -rfน่ากลัว xargs sudo rm -rfน่ากลัวอย่างไม่น่าเชื่อ

ฉันต้องการให้แน่ใจว่าไม่มีใครสามารถสร้างความเสียหายให้กับโฟลเดอร์ / ระบบอื่น ๆ โดยการสร้างไฟล์ที่ฉลาดที่จะลบ (ไม่ว่าจะโดยบังเอิญหรือโดยเจตนา) ฉันไม่รู้สิ่งที่ฉลาดชอบ:

file with / spaces.txt

ซึ่งอาจส่งผลให้น่ากลัวสุดsudo rm -rf /

แก้ไข:ความผิดพลาดของฉันชื่อไฟล์ไม่สามารถมีได้/ดังนั้นปัญหาเฉพาะนี้จะไม่เกิดขึ้น แต่คำถามเกี่ยวกับความเสี่ยงอื่น ๆ ที่ยังคงมีอยู่หรือไม่

นี่คือเหตุผลที่ฉันกำลังใช้--quoting-style=shell-alwaysงานสิ่งนี้ควรป้องกันไม่ให้เล่ห์เหลี่ยมกับไฟล์ที่มีช่องว่าง แต่ตอนนี้ฉันสงสัยว่าบางคนอาจฉลาดกว่าเดิมด้วยช่องว่างและเครื่องหมายคำพูดในชื่อไฟล์บางที

สคริปต์ของฉันปลอดภัยหรือไม่?


หมายเหตุ: ฉันต้องการsudoเพราะฉัน acessing โฟลเดอร์จากระยะไกล (จากไดรฟ์เครือข่ายที่แมปใช้mount) และฉันไม่สามารถใช้งานได้หากไม่มี sudo


3
คุณคิดว่าจะทำอะไรเช่นนี้printf -- '%s\0' /path/to/some/folder/* | head -zn -2 | xargs -0 rm?
ขับขี่เหล็ก

สามารถสร้างไฟล์ที่มีตัวละคร/ในชื่อฉันพยายามที่จะทำให้มันกลับมาที่นี่อีกครั้งหรือไม่
George Udosen

3
@George No ชื่อไฟล์ต้องไม่มีเครื่องหมายทับ
wjandrea

ดังนั้นเมื่อ OP บอกว่าคนฉลาดฉันสงสัย ...
George Udosen

6
เพียงเพราะคุณแยกวิเคราะห์lsผลลัพธ์นี่เป็นคำสั่งที่เขียนไม่ดีแม้ว่าจะมีการอ้างอิง lsฉันใช้สถานที่สำหรับการเรียงลำดับฉันคิดว่าฉันไม่เห็นว่าจุดประสงค์headในการลบ 2 รายการสุดท้าย (เว้นแต่คุณกำลังพยายามกำจัด.และ..ไม่อนุญาตให้ใช้ iirc ใดเป็นอาร์กิวเมนต์ในการrmต่อไปใช้เพียงfind /path/to/folder -type f deleteและ ไม่sudoถ้าคุณเรียกใช้จาก cron - cron อยู่ในระดับรากแล้ว
Sergiy Kolodyazhnyy

คำตอบ:


10

ใน Linux ตัวละครใด ๆ ที่เป็นชื่อไฟล์ที่ถูกต้องประกอบด้วยตัวละครยกเว้น:

  • \0 (ASCII NUL): ใช้สำหรับการยกเลิกสตริงใน C
  • / (เครื่องหมายสแลช): ใช้เพื่อแยกเส้นทาง

ดังนั้นวิธีการของคุณจะไม่ทำงานในหลายกรณีอย่างที่คุณสามารถจินตนาการได้เช่นมันจัดการกับการขึ้นบรรทัดใหม่ ( \n) ในชื่อไฟล์หรือไม่ ( คำแนะนำ: ไม่ )

หมายเหตุเล็กน้อย:

  • อย่าแยกls; ใช้เครื่องมือเฉพาะ (มีอย่างน้อยหนึ่งกรณีสำหรับการใช้งานส่วนใหญ่)
  • เมื่อต้องจัดการกับชื่อไฟล์ให้ลองใช้ประโยชน์จาก NUL ที่ถูกแยกออกโดยเครื่องมือ GNU เกือบทั้งหมดที่ทำงานกับข้อมูลดังกล่าว
  • ใช้ความระมัดระวังเมื่อวางท่อตรวจสอบให้แน่ใจว่าโปรแกรมทั้งสองสามารถเข้าใจการแยก NUL
  • เมื่อใดก็ตามที่คุณเรียกใช้xargsดูว่าคุณสามารถไปด้วยfind ... -exec; ในกรณีส่วนใหญ่คุณจะสบายใจเพียงfindลำพัง

ฉันคิดว่าสิ่งเหล่านี้จะทำให้คุณไปได้ในตอนนี้ steeldriverได้ให้แนวคิดที่แยกจากกันของ NUL ในข้อคิดเห็น ( printf -- '%s\0' /path/to/some/folder/* | head -zn -2 | xargs -0 rm) ใช้เป็นจุดเริ่มต้น


ขอบคุณสำหรับคำตอบของคุณ :) ฉันคิดว่าคุณควรพูดถึงความคิดเห็นของผู้ขับรถเหล็กแทนที่จะพูดถึงเพียงเพราะความคิดเห็นไม่ได้ถาวร ฉันจะพิจารณาด้วยfindเช่นกันขอบคุณสำหรับคำแนะนำ
เปโดร A

ฉันมีคำถามหนึ่งข้อ: ฉันไม่เข้าใจสิ่งที่คุณหมายถึงโดย "วิธีการของคุณจะไม่ทำงานแน่นอนในหลายกรณีที่คุณสามารถจินตนาการ" - "ไม่ทำงาน" ใน "ไม่ปลอดภัย" หรือ "ไม่ปลอดภัย"? เพราะ "วิธีการของคุณ" หมายถึงฉันและไม่ใช่ผู้ใช้ที่เป็นอันตรายและคำแถลงก่อนหน้าของคุณอยู่ในความโปรดปรานของฉันดังนั้นฉันจึงสับสน
เปโดร A

@PedroA คุณคือคุณ :) อย่างที่ฉันพูดเพราะตัวละครทุกตัวใช้ได้ยกเว้นตัวละครสองตัวที่กล่าวถึงคุณควรจะสามารถจินตนาการได้ว่ามีหลายกรณีที่lsวิธีการวิเคราะห์คำของคุณจะล้มเหลวเช่นคุณคำนึงถึงบรรทัดใหม่ในชื่อไฟล์หรือไม่?
heemayl

โอ้บรรทัดใหม่ในชื่อไฟล์ ... ฉันไม่ได้คิดอย่างนั้น หากคุณไม่รังเกียจที่จะเพิ่มคำตอบของคุณเช่นกัน :) ขออภัยที่ต้องถาม แต่จะhead -zทำอย่างไร? ฟังดูไร้สาระ แต่ฉันไม่มีmanหรือinfoใน linux container ของฉัน CoreOS ... ไม่พบในอินเทอร์เน็ตด้วย ฉันได้รับhead: invalid option 'z'
Pedro A

@PedroA Newline เป็นเพียงกรณีเดียวมีหลายอย่างเช่นคุณอาจเดาได้ คุณต้องการ GNU head(มาพร้อมกับ GNU coreutils) นี่คือเวอร์ชันออนไลน์: manpages.ubuntu.com/manpages/xenial/man1/head.1.html
heemayl

3

xargs สนับสนุนการอ้างอิงบางส่วน: ด้วยเครื่องหมายคำพูดเดี่ยว, เครื่องหมายคำพูดคู่หรือแบ็กสแลชซึ่งอนุญาตให้ยอมรับข้อโต้แย้งโดยพลการ but แต่ด้วยไวยากรณ์ที่แตกต่างจากไวยากรณ์ quoting คล้ายเชลล์ของบอร์น

การนำ GNU ไปใช้lsตามที่พบใน Ubuntu ไม่มีโหมดการอ้างใด ๆ ที่เข้ากันได้กับxargsรูปแบบการป้อนข้อมูล

มันls --quoting-style=shell-alwaysเข้ากันได้กับ ksh93, bash และ zsh shells quoting syntax แต่เฉพาะเมื่อเอาต์พุตของlsถูกตีความโดยเชลล์ในโลแคลเดียวกับที่lsเคยเป็นเมื่อมันส่งออก นอกจากนี้ควรหลีกเลี่ยงสถานที่บางแห่งเช่นที่ใช้ BIG5, BIG5-HKSCS, GBK หรือ GB18030

ดังนั้นด้วยกระสุนเหล่านั้นคุณสามารถทำได้จริง:

typeset -a files
eval "files=($(ls --quoting-style=shell-always))"
xargs -r0a <(printf '%s\0' "${files[@]:0:3}") ...

แต่นั่นมีข้อได้เปรียบเล็กน้อย:

files=(*(N))                 # zsh
files=(~(N)*)                # ksh93
shopt -s nullglob; files=(*) # bash

กรณีเดียวที่มันจะกลายเป็นประโยชน์คือเมื่อคุณต้องการใช้-tตัวเลือกในการlsจัดเรียงไฟล์ตาม mtime / atime / ctime หรือ/-S -Vแต่ถึงอย่างนั้นคุณก็อาจจะใช้zsh:

files=(*(Nom))

ตัวอย่างเช่นการจัดเรียงไฟล์ตาม mtime (ใช้oLสำหรับ-Sและnสำหรับ-V)

หากต้องการลบทั้งหมดยกเว้นไฟล์ปกติที่แก้ไขล่าสุดสองไฟล์:

rm -f -- *(D.om[3,-1])

¹ยังคงมีข้อจำกัดความยาว (โดยexecve()และในxargsการใช้งานที่ไม่ใช่ของ GNU บางตัวที่ต่ำกว่ามาก) และxargsการใช้งานที่ไม่ใช่ของ GNU บางตัวจะทำให้การป้อนข้อมูลที่มีลำดับไบต์ไม่ก่อตัวอักขระที่ถูกต้อง

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