ความแตกต่างระหว่าง cat และ '>' ถึงศูนย์ออกไฟล์


23

คำสั่งทั้งสองนี้แตกต่างกันหรือไม่เกี่ยวกับวิธีที่พวกเขาไปเกี่ยวกับการลบไฟล์เป็นศูนย์หรือไม่? วิธีหลังเป็นวิธีที่สั้นกว่าในการทำอดีตหรือไม่? เกิดอะไรขึ้นเบื้องหลัง

ทั้งสอง

$ cat /dev/null > file.txt

$ > file.txt 

ผล

-rw-r--r--  1 user  wheel  0 May 18 10:33 file.txt

คำตอบ:


28

cat /dev/null > file.txtคือการใช้งานที่ไร้ประโยชน์ของแมว

cat /dev/nullผลลัพธ์โดยทั่วไปในการcatแสดงผลอะไร ใช่มันใช้งานได้ แต่หลายคนขมวดคิ้วเพราะมันส่งผลให้เกิดการเรียกใช้กระบวนการภายนอกที่ไม่จำเป็น
มันเป็นหนึ่งในสิ่งเหล่านั้นที่เป็นเรื่องธรรมดาเพราะมันเป็นเรื่องธรรมดา

การใช้เพียงแค่> file.txtทำงานกับเชลล์ส่วนใหญ่ แต่มันไม่สามารถพกพาได้อย่างสมบูรณ์ หากคุณต้องการพกพาอย่างสมบูรณ์ต่อไปนี้เป็นทางเลือกที่ดี:

true > file.txt
: > file.txt

ทั้งสอง:และtrueไม่ส่งออกข้อมูลและเป็น shell builtins (ในขณะที่catเป็นยูทิลิตี้ภายนอก) ดังนั้นพวกเขาจึงมีน้ำหนักเบาและเหมาะสมกว่า

 

ปรับปรุง:

ตามที่ไทเลอร์กล่าวถึงในความคิดเห็นของเขายังมี>| file.txtไวยากรณ์

>เปลือกหอยส่วนใหญ่จะมีการตั้งค่าที่จะป้องกันไม่ให้พวกเขาจากการตัดทอนไฟล์ที่มีอยู่ผ่านทาง คุณต้องใช้>|แทน นี่คือเพื่อป้องกันข้อผิดพลาดของมนุษย์เมื่อคุณต้องการผนวกเข้าด้วย>>กัน set -Cคุณสามารถเปิดการทำงานกับ

ดังนั้นด้วยวิธีนี้ฉันคิดว่าวิธีที่ง่ายที่สุดเหมาะสมที่สุดและพกพาในการตัดไฟล์จะเป็น:

:>| file.txt

2
คำสั่งลำไส้ใหญ่ถูกกำหนดไว้ใน POSIX มันเป็นการดำเนินการที่มีอยู่เพื่อขยายบรรทัดคำสั่ง
kojiro

3
LOL "การทารุณกรรมแมว"
KM

2
@kojiro :ยังได้รับคำสั่งจาก POSIX ให้ติดตั้งในตัวและในความเป็นจริงแตกต่างจากtrueที่คิดว่าเป็น"พิเศษ" ในตัว
jw013

2
อย่าลืมเกี่ยวกับnoclobber >| fileเป็นการตัดทอนที่ชัดเจนมากขึ้น
tylerl

1
ไม่มีtrueไม่จำเป็นต้องเป็น builtin และมันไม่ได้เป็นแบบดั้งเดิม :ถูกสร้างขึ้นในทุก ๆ เชลล์ของตระกูล Bourne :เป็น builtin พิเศษต่อ POSIX (ดังนั้น: > fileจะออกจากเชลล์เช่นถ้าfileไม่สามารถเปิดสำหรับการเขียนใน POSIX เชลล์) และtrueไม่ได้ POSIX ยังกล่าวถึงที่:อาจมีประสิทธิภาพมากกว่าtrueในบางระบบ
Stéphane Chazelas

23

ในแง่ของการพกพา:

                      Bourne POSIX  zsh    csh/tcsh  rc/es  fish
> file                Y      Y      N(1)   N(1)      N      N
: > file              N/Y(2) Y(3)   Y      Y(4)      N(5)   N(5)
true > file           Y(5)   Y      Y      Y(5)      Y(5)   Y(5)
cat /dev/null > file  Y(5)   Y      Y(5)   Y(5)      Y(5)   Y(5)
eval > file           Y(3,8) Y(3)   Y      Y(6)      Y      Y
cp /dev/null file (7) Y(5)   Y      Y(5)   Y(5)      Y(5)   Y(5)
printf '' > file      Y(5)   Y      Y      Y(5)      Y(5)   Y

หมายเหตุ:

  1. ยกเว้นในshหรือkshจำลองสำหรับการเปลี่ยนเส้นทางโดยไม่มีคำสั่งใน zsh คำสั่งเริ่มต้นจะถือว่า (เพจเจอร์สำหรับการเปลี่ยนเส้นทาง stdin เท่านั้นcatมิฉะนั้น) ที่สามารถปรับด้วยตัวแปร NULLCMD และ READNULLCMD นั่นเป็นแรงบันดาลใจจากคุณสมบัติที่คล้ายกันใน(t)csh
  2. การเปลี่ยนเส้นทางครั้งแรกไม่ได้ดำเนินการ:ใน UnixV7 ซึ่ง:ถูกตีความไปครึ่งทางระหว่างผู้นำความคิดเห็นและคำสั่งที่เป็นโมฆะ หลังจากนั้นพวกเขาและชอบสำหรับ builtins ทั้งหมดหากการเปลี่ยนเส้นทางล้มเหลวนั่นจะออกจากเชลล์
  3. :และevalเป็นบิวด์อินพิเศษหากการเปลี่ยนเส้นทางล้มเหลวนั่นจะออกจากเชลล์ ( bashเฉพาะในโหมด POSIX)
  4. ที่น่าสนใจ(t)cshคือการกำหนดป้ายกำกับว่าง (สำหรับgoto) ดังนั้นgoto ''จะมีสาขาที่นั่น หากการเปลี่ยนเส้นทางล้มเหลวนั่นจะเป็นการออกจากเชลล์
  5. เว้นแต่ / ถ้าคำสั่งที่เกี่ยวข้องมีอยู่ใน$PATH( :โดยทั่วไปไม่ได้; true, cat, cpและprintfโดยทั่วไปจะ (POSIX ต้องการให้พวกเขา))
  6. หากการเปลี่ยนเส้นทางล้มเหลวนั่นจะเป็นการออกจากเชลล์
  7. หากfileเป็น symlink ไปยังไฟล์ที่ไม่มีอยู่cpการใช้งานบางอย่างเช่น GNU's จะปฏิเสธที่จะสร้างมันขึ้นมา
  8. เชลล์เป้าหมายรุ่นแรกไม่รองรับการเปลี่ยนเส้นทางบิวอิน

ในแง่ของความชัดเจน:

(ส่วนนี้มีความคิดเห็นสูง)

  • > file. ที่>มีลักษณะเหมือนพรอมต์หรือความคิดเห็นมากเกินไป นอกจากนี้คำถามที่ฉันจะถามเมื่ออ่านว่า (และเชลล์ส่วนใหญ่จะบ่นเกี่ยวกับสิ่งเดียวกัน) คือผลลัพธ์อะไรที่คุณเปลี่ยนเส้นทาง? .
  • : > file. :เรียกว่าคำสั่ง no-op เพื่อให้อ่านได้ทันทีว่าเป็นการสร้างไฟล์เปล่า อย่างไรก็ตามที่นี่อีกครั้งที่:สามารถพลาดและ / หรือมองว่าเป็นพรอมต์
  • true > file: บูลีนทำอะไรกับการเปลี่ยนเส้นทางหรือเนื้อหาไฟล์ ที่นี่มีความหมายอะไร? เป็นสิ่งแรกที่อยู่ในใจของฉันเมื่อฉันอ่านมัน
  • cat /dev/null > file. Concatenate /dev/nullเข้าfile? catถูกมองเห็นได้บ่อยเท่าที่เป็นคำสั่งเพื่อการถ่ายโอนข้อมูลเนื้อหาของไฟล์ที่ยังคงสามารถทำให้ความรู้สึก: การถ่ายโอนข้อมูลเนื้อหาของไฟล์ที่ว่างเปล่าลงไปในfile , bit เช่นวิธีที่ซับซ้อนที่จะพูดcp /dev/null fileแต่ก็ยังเข้าใจ
  • cp /dev/null file. คัดลอกเนื้อหาของแฟ้มที่ว่างเปล่าfileไป ทำให้รู้สึกว่ามีใครบางคนไม่ทราบว่าวิธีcpจะหมายถึงการทำตามค่าเริ่มต้นอาจจะคิดว่าคุณกำลังพยายามที่จะทำให้อุปกรณ์ได้เป็นอย่างดีfilenull
  • eval > fileeval '' > fileหรือ fileทำงานอะไรและเปลี่ยนเส้นทางการส่งออกไปยัง ทำให้รู้สึกถึงฉัน แปลกที่มันไม่ใช่สำนวนสามัญ
  • printf '' > file: ไม่พิมพ์อะไรลงในไฟล์อย่างชัดเจน คนที่เหมาะสมที่สุดสำหรับฉัน

ในแง่ของประสิทธิภาพ

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

evalรับประกันว่าจะสร้างขึ้นในทุกเชลล์ :มีในตัวทุกที่ที่มี (ชอบ Bourne / csh) trueถูกสร้างขึ้นในเชลล์ที่เหมือนบอร์นเท่านั้น

printffishถูกสร้างขึ้นในบอร์นที่ทันสมัยที่สุดเหมือนเปลือกหอยและ

cpและcatโดยทั่วไปไม่ได้มีอยู่แล้ว

ตอนนี้cp /dev/null fileไม่เรียกใช้การเปลี่ยนเส้นทางของเชลล์ดังนั้น:

find . -exec cp /dev/null {} \;

กำลังจะมีประสิทธิภาพมากกว่า:

find . -exec sh -c '> "$1"' sh {} \;

(แม้ว่าจะไม่จำเป็นกว่า:

find . -exec sh -c 'for f do : > "$f"; done' sh {} +

)

ส่วนตัว

โดยส่วนตัวแล้วฉันใช้: > fileในกระสุนที่มีลักษณะคล้ายบอร์นและไม่ได้ใช้สิ่งใดนอกจากหอยที่มีลักษณะคล้ายบอร์นในปัจจุบัน


เกี่ยวกับdd of=file count=0อะไร
kojiro

2
@kojiro ด้วยการใช้งานบางอย่างของdd(เช่น Solaris 10 อย่างน้อย) count=0จะถูกละเว้น dd if=/dev/null of=fileจะเป็นแบบพกพามากขึ้น ไม่ว่าในกรณีใด ๆ นั่นเป็นอิสระจากเชลล์
Stéphane Chazelas

ตกลง แต่มันก็ไม่สมควรที่จะได้รับการรวมเข้าไว้cp /dev/null fileด้วยกันใช่ไหม?
kojiro

2
@kojiro cp /dev/null fileเป็นสำนวนสามัญ ฉัน จำกัด เฉพาะสิ่งเหล่านั้นจุดไม่ได้แสดงวิธีที่เป็นไปได้ทั้งหมด
Stéphane Chazelas

5

คุณอาจต้องการดูtruncateซึ่งทำอย่างนั้น: ตัดไฟล์

ตัวอย่างเช่น:

truncate --size 0 file.txt

true > file.txtนี่อาจจะช้ากว่าการใช้

จุดหลักของฉันคือ: truncateมีไว้สำหรับการตัดทอนไฟล์ในขณะที่ใช้> มีผลข้างเคียงของการตัดทอนไฟล์


2
ตัดเป็นสิ่งที่ดีเมื่อคุณต้องการที่จะตัดไฟล์อย่างอื่นที่ไม่ใช่ 0. ที่กล่าวว่าการได้โดยไม่ต้องมีเปลือกเป็นคำสั่งที่แปลก: คุณสามารถอธิบายบริบทที่truncateจะใช้ได้ แต่ไม่>ว่ามิได้unistdห้องสมุด C จะมี?
kojiro

ไม่ได้จริงๆ อาจมีทางออกที่สง่างามยิ่งขึ้นสำหรับสคริปต์หรือภาษาการเขียนโปรแกรมทั้งหมดที่มี
เฟเบียน

3
truncateเป็นยูทิลิตี้ FreeBSD ซึ่งเพิ่มเมื่อเร็ว ๆ นี้ (2008) ใน coreutils ของ GNU (แม้ว่า--sizeตัวเลือกแบบยาวของ GNU คือ GNU เฉพาะ) ดังนั้นจึงไม่สามารถใช้ได้ในระบบที่ไม่ใช่ GNU หรือ FreeBSD และไม่มีในระบบ GNU รุ่นเก่า ฉันจะไม่พูดแบบพกพา cp /dev/null fileจะทำงานโดยไม่มีการเปลี่ยนเส้นทางของเชลล์และพกพาได้มากกว่า
Stéphane Chazelas

ตกลงฉันจะลบความคิดเห็นการพกพานั้น แม้ว่าคำจำกัดความของคุณที่ผ่านมาดูเหมือนจะแตกต่างกัน
เฟเบียน

2

คำตอบนั้นขึ้นอยู่กับว่าfile.txtเป็นอย่างไรและกระบวนการเขียนถึงมันอย่างไร!

ฉันจะอ้างถึงกรณีการใช้งานทั่วไป: คุณมีไฟล์บันทึกการเติบโตที่เรียกว่าfile.txtและต้องการหมุนมัน

ดังนั้นคุณคัดลอกตัวอย่างเช่นfile.txtเข้าfile.txt.save, file.txtตัดแล้ว

ในสถานการณ์สมมตินี้หากไฟล์ไม่ได้ถูกเปิดโดยanother_process(เช่น: another_processอาจเป็นโปรแกรมที่ส่งออกไปยังไฟล์นั้นเช่นโปรแกรมบันทึกบางอย่าง) ดังนั้นข้อเสนอ 2 รายการของคุณจะเทียบเท่ากันและทั้งสองทำงานได้ดี (แต่ตัวที่สองชอบ แรก "cat / dev / null> file.txt" เป็นการใช้ประโยชน์ของ Cat และยังเปิดและอ่าน / dev / null)

แต่ปัญหาที่แท้จริงคือถ้าother_processยังใช้งานอยู่และยังคงมีหมายเลขอ้างอิงที่เปิดอยู่ที่ไปยัง file.txt

จากนั้นมี 2 กรณีหลักเกิดขึ้นขึ้นอยู่กับวิธีother processเปิดไฟล์:

  • หากother_processเปิดขึ้นตามปกติแล้วหมายเลขอ้างอิงจะยังคงชี้ไปที่ตำแหน่งเดิมในไฟล์เช่นที่ออฟเซ็ต 1200 ไบต์ การเขียนครั้งต่อไปจะเริ่มที่ offset 1200 และดังนั้นคุณจะมีไฟล์อีก 1200 ไบต์ (+ ไฟล์อื่น ๆ ที่โพรเซสเขียนไว้), ด้วย 1200 ตัวอักษรโมฆะ! ไม่ใช่สิ่งที่คุณต้องการฉันเข้าใจ

  • หากother_processเปิดfile.txtใน "ผนวกโหมด" จากนั้นทุกครั้งที่เขียนตัวชี้จะพยายามหาจุดสิ้นสุดของไฟล์ ดังนั้นเมื่อคุณตัดทอนมันมันจะ "ค้นหา" จนถึงไบต์ 0 และคุณจะไม่มีผลข้างเคียงที่ไม่ดี! นี่คือสิ่งที่คุณต้องการ (... ปกติแล้ว!)

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

ข้อมูลอ้างอิง: /programming//a/16720582/1841533สำหรับคำอธิบายที่สะอาดกว่าและเป็นตัวอย่างสั้น ๆ ที่ดีเกี่ยวกับความแตกต่างระหว่างการบันทึกแบบปกติและการผนวกโหมดที่/programming//a/984761/1841533


2
คำตอบนี้มีน้อยมากที่เกี่ยวข้องหรือตอบคำถาม ความแตกต่างระหว่าง a cat /dev/null > fileและ a > fileคือ a cat /dev/nullและทำให้ไม่มีความแตกต่างกับไฟล์
jw013

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

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

1

ฉันชอบสิ่งนี้และใช้งานบ่อยเพราะมันดูสะอาดและไม่เหมือนใครบางคนกดปุ่มย้อนกลับโดยไม่ได้ตั้งใจ:

echo -n "" > file.txt

ควรเป็นแบบในตัวด้วยหรือไม่


3
มีหลายวิธีในการ zero-out ไฟล์ ฉันคิดว่า KM มีเพียงสนใจที่จะเข้าใจความแตกต่างระหว่างสองวิธีที่แสดงในคำถาม
drs

6
echoการใช้งานหลายอย่างไม่สนับสนุน-n(และจะแสดงผล-n<SPC><NL>ที่นี่printf '' > file.txtจะเป็นแบบพกพามากขึ้น (อย่างน้อยในระบบที่ทันสมัย ​​/ POSIX)
Stéphane Chazelas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.