ทำไมคุณถึงต้องการ `cat / dev / null> / var / log / messages`


77

ในหน้าตัวอย่างสคริปต์ทุบตีผู้เขียนนำเสนอสคริปต์นี้:

# Cleanup
# Run as root, of course.

cd /var/log
cat /dev/null > messages
cat /dev/null > wtmp
echo "Log files cleaned up."

ทำไมคุณต้องcat /dev/nullทำอะไร ฉันไม่เข้าใจสิ่งที่ตั้งใจไว้ที่นี่ (มันใช้while TRUE; sleep 1; elihwเพื่อ{some busy program}อะไร) แต่ผู้เขียนเรียกมันว่า“ ไม่มีอะไรผิดปกติ”

คำตอบ:


41

โดยทั่วไปcat /dev/null > [something]เมื่อคุณต้องการลบเนื้อหาไฟล์ในขณะที่มั่นใจว่าไม่มีความเสี่ยงต่อการหยุดชะงักของสถานะไฟล์จริง เนื้อหาของไฟล์จะถูกล้างอย่างชัดเจนโดยcat /dev/nullตัวไฟล์เอง - ตามที่มีอยู่และเป็นที่รู้จักในระบบไฟล์ที่อยู่ - จะยังคงมีหมายเลขไอโหนดเดียวกันกรรมสิทธิ์และสิทธิ์

ในกรณีของไฟล์บันทึกอาจเป็นไปได้ว่าไฟล์บันทึกของตัวเองถูกทำเครื่องหมายว่า“ กำลังใช้” โดยกระบวนการอื่น ดังนั้นการทำเช่นrm /var/log/messages && touch /var/log/messagesจะเป็นการขัดขวางกระบวนการอื่น ๆ และอาจทำให้กระบวนการที่ใช้งานทำให้หายใจไม่ออก ความหมายกระบวนการที่ถูกล็อกไปยังหมายเลขไอโหนดเฉพาะที่เชื่อมต่อกับไฟล์/var/log/messagesอาจทำให้ตกใจและพูดว่า“ เฮ้! เกิดอะไรขึ้นกับ/var/log/messages! "แม้ว่าไฟล์จะยังอยู่ที่นั่น ไม่พูดถึงปัญหาที่อาจเกิดขึ้นกับความเป็นเจ้าของและสิทธิ์ที่ถูกสร้างขึ้นอย่างไม่ถูกต้อง

เนื่องจากความไม่แน่นอนในการใช้งาน / รัฐของไฟล์ที่ใช้cat /dev/null > [something]เป็นที่ต้องการของผู้ดูแลระบบที่ต้องการที่จะล้างออกบันทึก แต่ไม่ต้องการที่จะอาจรบกวนการทำงานของกระบวนการที่มีอยู่แล้ว

นอกจากนี้ในบริบทของหน้าคุณเชื่อมโยงไปยังผู้เขียนระบุต่อไปนี้:

ไม่มีอะไรผิดปกติที่นี่มีเพียงชุดคำสั่งที่สามารถเรียกใช้ได้อย่างง่ายดายทีละรายการจากบรรทัดคำสั่งบนคอนโซลหรือในหน้าต่างเทอร์มินัล ข้อดีของการวางคำสั่งในสคริปต์ไปไกลเกินกว่าที่ไม่ต้องพิมพ์ซ้ำครั้งแล้วครั้งเล่า

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


10
@jlliagre สิ่งเดียวที่ถูก "ทำให้มีชีวิต" คือบริบทของคำถามที่มุ่งเน้นไปที่สาเหตุที่ผู้เขียนต้นฉบับทำเช่นนั้น หากคุณรู้สึกไม่สบายใจที่จะกำจัด "ตำนาน" โปรดโพสต์คำตอบที่ให้บริบทสำหรับวิธีการเข้ารหัสของผู้เขียนต้นฉบับรวมถึงมุมมองว่าทำไมคุณถึงเชื่อว่ามันสามารถถูกแทนที่ด้วยวิธีอื่น
JakeGould

7
คำตอบของ @jlliagre Cyrus ไม่ได้ตอบคำถามหลักว่าทำไมผู้เขียนต้นฉบับจะใช้วิธีการนั้นหรือเหตุผลที่อยู่เบื้องหลัง การสอนที่กล่าวถึงค่อนข้างเก่าและยอมรับอย่างสมเหตุสมผล มันไม่ถูกต้องและไม่ทำให้เป็น“ ตำนานเมือง” มันเป็นวิธีที่รหัสของคนคนหนึ่งกับวิธีที่คนอื่นรหัส ง่ายเหมือนที่ มันเป็นปัญหาสไตล์ที่ไม่มีผลกระทบด้านลบต่อความน่าเชื่อถือหรือประสิทธิภาพ
JakeGould

3
truncate -s 0จะทำสิ่งเดียวกันและเป็นสำนวนน้อย อย่างไรก็ตามโปรแกรมเมอร์เชลล์เป็นกลุ่มอนุรักษ์นิยมและบางคนอาจพบว่าระบบเก่าพอหรือแปลกประหลาดพอที่จะขาดคำสั่งนั้น
Schwern

5
@skift cat /dev/null > /foo/barตัดทอนไฟล์; echo "" > /foo/barตัดมันแล้วเขียนอักขระบรรทัดใหม่
David

2
ข้อดีอีกประการของวิธีนี้มากกว่าการใช้ rm & touch ก็คือการรักษาความเป็นเจ้าของและการอนุญาตไว้
jjmontes

121

ทำไมคุณถึง cat / dev / null ไปยังอะไร?

คุณจะทำเช่นนั้นเพื่อตัดทอนเนื้อหาไฟล์ในขณะที่ยังคง inode เหมือนเดิม โปรแกรมทั้งหมดที่เปิดไฟล์นั้นไว้สำหรับการอ่านหรือเขียนจะไม่ได้รับผลกระทบจากความจริงที่ว่าขนาดไฟล์จะถูกรีเซ็ตเป็นศูนย์

ทางเลือกที่พบบ่อยปลอมเป็นการลบไฟล์จากนั้นสร้างใหม่อีกครั้ง:

rm file
touch file

หรือคล้ายกัน:

mv file file.old
gzip file.old
touch file

ปัญหาคือวิธีการเหล่านี้ไม่ได้ป้องกันไม่ให้ไฟล์เก่าถูกเขียนโดยกระบวนการใดก็ตามที่มีไฟล์ที่ถูกลบเปิดในเวลาที่ลบ เหตุผลที่อยู่ภายใต้ระบบไฟล์ Unix เมื่อคุณลบไฟล์คุณจะยกเลิกการเชื่อมโยงชื่อ (พา ธ ) จากเนื้อหา (inode) เท่านั้น ไอโหนดจะยังคงมีชีวิตอยู่ตราบใดที่มีกระบวนการที่เปิดให้อ่านหรือเขียน

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

วิธีแรกcat /dev/null > fileให้บรรลุเป้าหมายอย่างถูกต้องอย่างไรก็ตามแม้จะมีตำนานเมืองที่หวงแหน แต่cat /dev/nullส่วนหนึ่งก็ไม่มีประโยชน์อะไรเลย มันเปิดไฟล์หลอกซึ่งว่างเปล่าโดยการออกแบบมันล้มเหลวในการอ่านอะไรจากมันและในที่สุดก็ออกจาก การใช้คำสั่งนี้จะเป็นการสูญเสียการกดแป้นพิมพ์, ไบต์, การเรียกของระบบและรอบการทำงานของ CPU และสามารถถูกแทนที่โดยไม่มีการเปลี่ยนแปลงการทำงานใด ๆ โดยคำสั่ง no-op ที่เร็วขึ้นอย่างไม่ต้องสงสัย:หรือแม้กระทั่ง

ให้ฉันลองอุปมาอุปมัยเพื่ออธิบายว่าไร้ประโยชน์cat /dev/nullอย่างไร สมมติว่าเป้าหมายของคุณคือการล้างแก้ว

  • คุณลบของเหลวใด ๆ ออกจากมันก่อน นั่นเพียงพอแล้วและเป็นอย่างแม่นยำสิ่งที่ ( > file) ได้รับจากการเปลี่ยนเส้นทางข้อเท็จจริงจะถูกประมวลผลก่อนเสมอ

  • จากนั้นคุณเลือกขวดเปล่า ( /dev/null) แล้วเทลงในแก้วเปล่า ( cat) นี่คือขั้นตอนที่ไม่มีจุดหมาย ...

หากคุณอ่านเอกสารที่เชื่อมโยงถึงจุดสิ้นสุดคุณอาจสังเกตเห็นความคิดเห็นในบรรทัดนี้จากสคริปต์ที่ปรับปรุงแล้ว:

    cat / dev / null> wtmp #   ':> wtmp' และ '> wtmp' มีผลเหมือนกัน

พวกเขามีแน่นอน; แย่มากcat /dev/nullถูกเก็บไว้ในรหัส

นั่นหมายความว่ารหัสต่อไปนี้จะทำงานกับเชลล์ทั่วไปทั้งหมด (ทั้งcshและshตระกูล):

cd /var/log
: > messages
: > wtmp
echo "Log files cleaned up."

และสิ่งนี้จะทำงานร่วมกับเปลือกหอยทั้งหมดโดยใช้ไวยากรณ์บอร์นเช่นash, bash, ksh, zshและชอบ:

cd /var/log
> messages
> wtmp
echo "Log files cleaned up."

อย่างไรก็ตามโปรดทราบว่าด้วยเชลล์ Bourne ก่อนหน้า POSIX คำสั่งใด ๆ เหล่านี้รวมถึงcat /dev/nullจะไม่ตัดไฟล์ถ้ามันถูกเขียนหลังจากนั้นโดยสคริปต์เชลล์ที่กำลังรันอยู่ต่อท้าย แทนที่จะเป็นไฟล์ศูนย์ไบต์นั่นจะเป็นไฟล์กระจัดกระจายที่มีขนาดไม่เปลี่ยนแปลง เช่นเดียวกันจะเกิดขึ้นหากไฟล์ถูกเขียนโดยกระบวนการที่กำลังค้นหาตำแหน่งที่คิดว่าเป็นไฟล์ปัจจุบันก่อนที่จะเขียน

ระวังด้วยว่าโซลูชันทางเลือกบางตัวมักแนะนำให้ตัดทอนไฟล์ที่มีข้อบกพร่อง

  • ทั้งสองอย่างต่อไปนี้ไม่ทำงาน ไฟล์ผลลัพธ์ไม่ว่างเปล่า แต่มีบรรทัดว่าง นี้จะทำลายไฟล์บันทึกเช่นwtmpเก็บบันทึกความกว้างคงที่

    echo > file
    echo "" > file
  • ตัวถัดไปที่ใช้shตัวเลือกBSD ไม่ใช่แบบพกพา POSIX ไม่ได้ระบุตัวเลือกที่อนุญาตสำหรับเสียงก้องดังนั้นคุณอาจท้ายไฟล์ที่มีบรรทัดที่มี " -n":

    echo -n > file
  • นั่นไม่ใช่แบบพกพาอย่างใดอย่างหนึ่งโดยใช้shลำดับSystem V escape เชลล์บางตัวจะสร้างไฟล์ที่มีบรรทัดที่มี " \c":

    echo "\c" > file
  • ใช้คำสั่งที่ออกแบบมาเพื่อทำงาน ปัญหาที่ใช้truncateไม่สามารถเคลื่อนย้ายได้เนื่องจากคำสั่งนี้ไม่ได้ถูกระบุโดย POSIX อาจหายไปจากระบบ Unix / Linux

    truncate -s 0

ในที่สุดนี่คือทางเลือกสองทางที่พกพาได้และจะทำงานได้อย่างถูกต้อง:

  • พิมพ์สตริงว่างไปยังไฟล์อย่างชัดเจน:

    printf "" > file
  • การใช้trueคำสั่งซึ่งเทียบเท่ากับ no-op อย่างใดอย่างหนึ่งถึง:แม้ว่าจะอ่านง่ายขึ้น:

    true > file

1
@JonathanLeffler ฉันเชื่อว่ามันเป็นส่วนหนึ่งของcshการใช้งานในปัจจุบันทั้งหมดแม้ว่าจะไม่ได้มีการบันทึกไว้ จาก Solaris หน้าคู่มือcsh : Null command. This command is interpreted, but performs no action.ฉันไม่พบการพูดถึงสิ่งเดียวกันในtcshหน้าคู่มือหรือ BSD ดั้งเดิมcshแต่ไวยากรณ์นี้อาจใช้งานได้เสมอ
jlliagre

6
เหตุผลหนึ่งในการเขียนcat /dev/nullคือการทำให้ความตั้งใจของคุณชัดเจน
Davidmh

1
@Davidmh นั่นจะสมเหตุสมผล แต่คำสั่งของคุณไม่ได้ต่อต้านการตรวจสอบข้อเท็จจริง ฉันได้สังเกตสำนวนเปลือกนี้เป็นเวลาสองทศวรรษ เมื่อฉันมีโอกาสถามผู้เขียนถึงเหตุผลเบื้องหลังฉันมักจะได้รับทฤษฎีที่ไม่/dev/nullถูกต้องเกี่ยวกับการใช้วิธีที่มีประสิทธิภาพในการฉีดเลขศูนย์ไบต์ แต่ก็มีความน่าเชื่อถือมากกว่าการใช้:หรือไม่มีอะไรเลย ในหน้านี้ไซรัสตอบคำถามสั้น ๆ แต่ตรงประเด็นมีคะแนนโหวตเป็นศูนย์ในขณะที่เจคกูลล์คนหนึ่งที่กำลังท้าทายความจริงcat /dev/nullก็คือไม่ต้องใช้ op (ดูความคิดเห็นของเรา) มีคะแนนโหวตอย่างน้อยสี่ครั้ง
jlliagre

2
@jlliagre ความรู้เกี่ยวกับเชลล์ของฉันนั้นค่อนข้างพื้นฐานดังนั้นฉันอาจไม่ใช่เป้าหมายประชากรที่ดีที่สุด แต่ตัวเปล่า>หรือ:ไม่ชัดเจน ฉันยอมรับว่ามันเป็นความอัปยศที่ตำนานมีการเผยแพร่เนื่องจากการใช้งาน
Davidmh

4
@Davidmh หากคุณต้องการบางสิ่งบางอย่างที่ชัดเจนก่อนการเปลี่ยนเส้นทางฉันขอแนะนำprintf "" > fileว่าแบบพกพา (POSIX) และเบาเท่าที่มักจะนำมาใช้เป็นเชลล์ในตัว
jlliagre

6

มันเป็นวิธีที่ยุ่งยากในการทำให้ไฟล์มีขนาดเป็นศูนย์

cd /var/log
> messages
> wtmp
echo "Log files cleaned up."

ไวยากรณ์นี้จะไม่ทำงานในทุกเชลล์
reinierpost

2
แก้ไข. คำถามถูกแท็กด้วย "bash" เท่านั้น
Cyrus

@reinierpost มันจะใช้ได้กับกระสุนสไตล์ Bourne ทั้งหมดใช่มั้ย ไม่ต้องกังวลcshหรอก
Barmar

: > messagesยังใช้งานได้ :หรือtrueเป็นตัวเลือกที่ชัดเจนยิ่งขึ้นสำหรับคำสั่งที่พิมพ์อะไรและกลับมาจริง
Peter Cordes

-3

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

echo -n > /var/log/messages

(เพิ่ม -n เพื่อหลีกเลี่ยงการขึ้นบรรทัดใหม่)


3
นี่เป็นสิ่งที่เข้าใจได้มากกว่า แต่น่าเสียดายที่ไม่เทียบเท่ากัน มันก็จะทำลายฟังก์ชันการทำงานเช่นในwtmpกรณี ดูคำตอบที่อัปเดตของฉัน
jlliagre

echo -n หลีกเลี่ยงการขึ้นบรรทัดใหม่
bbaassssiiee

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