ทำไม `cp 'ถูกออกแบบมาเพื่อเขียนทับไฟล์ที่มีอยู่อย่างเงียบ ๆ ? [ปิด]


30

ฉันทดสอบcpด้วยคำสั่งต่อไปนี้:

$ ls
first.html   second.html  third.html

$ cat first.html
first

$ cat second.html
second

$ cat third.html
third

จากนั้นฉันก็คัดลอกfirst.htmlไปที่second.html:

$ cp first.html second.html

$ cat second.html
first

ไฟล์second.htmlถูกเขียนทับอย่างเงียบ ๆ โดยไม่มีข้อผิดพลาด อย่างไรก็ตามถ้าฉันทำมันใน GUI บนเดสก์ท็อปโดยการลากและวางไฟล์ด้วยชื่อเดียวกันมันจะถูกfirst1.htmlต่อท้ายโดยอัตโนมัติ วิธีนี้จะหลีกเลี่ยงการเขียนทับไฟล์ที่มีอยู่โดยไม่ตั้งใจ

ทำไมไม่cpทำตามรูปแบบนี้แทนที่จะเขียนทับไฟล์อย่างเงียบ ๆ ?


10
ฉันนึกภาพผู้ออกแบบคอร์หลักเท่านั้นที่สามารถตอบคำถามได้อย่างแท้จริง แต่มันก็เป็นแบบที่มันใช้งานได้ในตอนนี้ โดยปกติแล้วแอปจะถูกสร้างขึ้นโดยสมมติว่าผู้ใช้หมายถึงสิ่งที่พวกเขากำลังทำอยู่และเพื่อลดการกระตุ้นเตือนพิเศษ หากคุณต้องการเปลี่ยนพฤติกรรมให้นามแฝง 'cp' เป็น 'cp -i' หรือ 'cp -n'
kevlinux

8
@kevlinux coreutils devs เป็นเพียงการนำมาตรฐาน POSIX มาใช้
Kusalananda

17
เพราะเมื่อมันถูกออกแบบมาผู้คนต้องการที่จะกระชับเท่าที่จะเป็นไปได้กับสิ่งที่พวกเขาทำ (จึงไม่คัดลอก CP) และรู้ว่าสิ่งที่พวกเขาทำและเมื่อพวกเขาทำผิดพลาดพวกเขาไม่ได้พยายามตำหนิเครื่องมือ มันเป็นคนที่แตกต่างกันโดยสิ้นเชิงในตอนนั้นที่ทำคอมพิวเตอร์ มันเหมือนถามว่าทำไมมีดผ่าตัดสำหรับศัลยแพทย์หัวใจสามารถตัดมือเช่นกัน
PlasmaHH

4
Unix ได้รับการออกแบบโดยผู้เชี่ยวชาญด้านคอมพิวเตอร์โดยมีข้อสันนิษฐานว่าผู้ใช้รู้ว่าเขาทำอะไรอยู่ ระบบปฏิบัติการจะทำสิ่งที่ผู้ใช้บอกถ้าเป็นไปได้ - โดยไม่ต้องจับมือผู้ใช้และไม่ขอการยืนยันที่ไม่สิ้นสุด หากการดำเนินการเขียนทับสิ่งใดสิ่งหนึ่งก็ถือว่าเป็นสิ่งที่ผู้ใช้ต้องการ โปรดจำไว้ว่านี่คือต้นปี 1970 - pre-MS DOS, Windows และคอมพิวเตอร์ที่บ้าน - การชี้นำและจับมือผู้ใช้ทุกขั้นตอนยังไม่เป็นที่ทราบกันทั่วไป นอกจากนี้การใช้เครื่องพิมพ์ดีดเป็นเครื่องเทอร์มินัลการขอคำยืนยันมักจะยุ่งยากเกินไป
Baard Kopperud

10
อย่านามแฝงcpไปcp -iหรือคล้ายกันเพราะคุณจะได้รับใช้ในการมีความปลอดภัยสุทธิทำให้ระบบที่มันไม่สามารถใช้ได้ (ส่วนใหญ่) ที่มีความเสี่ยงมากขึ้น ดีกว่าที่จะสอนตัวเองเป็นประจำcp -iฯลฯ หากนั่นคือสิ่งที่คุณต้องการ
Reid

คำตอบ:


52

พฤติกรรมการเขียนทับเริ่มต้นของcpถูกระบุใน POSIX

  1. หาก source_file เป็นไฟล์ประเภทปกติให้ทำตามขั้นตอนต่อไปนี้:

    3.a. ลักษณะการทำงานไม่ได้รับการระบุหากมีอยู่ใน dest_file และเขียนโดยขั้นตอนก่อนหน้า มิฉะนั้นหากมี dest_file อยู่จะต้องดำเนินการตามขั้นตอนต่อไปนี้:

    3.ai หากตัวเลือก -i มีผลบังคับใช้ยูทิลิตี้ cp จะเขียนข้อความแจ้งข้อผิดพลาดมาตรฐานและอ่านบรรทัดจากอินพุตมาตรฐาน หากการตอบสนองไม่ได้รับการยืนยัน cp จะไม่ทำอะไรมากกับ source_file และไปยังไฟล์ที่เหลืออยู่

    3.a.ii. ไฟล์ descriptor สำหรับ dest_file จะต้องได้รับจากการดำเนินการเทียบเท่ากับฟังก์ชั่น open () ที่กำหนดไว้ในปริมาณระบบอินเตอร์เฟซของ POSIX.1-2017 เรียกว่าการใช้ dest_file เป็นอาร์กิวเมนต์เส้นทางและ bitwise-inclusive OR ของ O_WRONLY และ O_TRUNC เป็น อาร์กิวเมนต์ oflag

    3.a.iii หากความพยายามในการขอรับไฟล์ descriptor ล้มเหลวและอ็อพชัน -f มีผลบังคับใช้ cp จะพยายามลบไฟล์โดยดำเนินการเทียบเท่ากับฟังก์ชัน unlink () ที่กำหนดไว้ในระดับเสียงของอินเตอร์เฟซระบบ POSIX.1-2017 ที่เรียกว่าใช้ dest_file เป็นอาร์กิวเมนต์ของเส้นทาง หากความพยายามนี้สำเร็จ cp จะดำเนินการต่อด้วยขั้นตอนที่ 3b

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

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

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

เมื่อมาตรฐาน POSIX ถูกเขียนก่อนหน้านี้ได้รับการก่อตั้งขึ้นอย่างมั่นคงและนักเขียนของมาตรฐานก็ตระหนักดีถึงคุณงามความดีของไม่หมดหลังเข้ากันได้

นอกจากนี้ตามที่ผู้อื่นได้อธิบายไว้ผู้ใช้สามารถเพิ่ม / เปิดใช้งานคุณลักษณะเหล่านั้นด้วยตนเองโดยใช้นามแฝงของเชลล์หรือแม้กระทั่งโดยการสร้างcpคำสั่งการแทนที่และปรับเปลี่ยน$PATHเพื่อค้นหาการแทนที่ก่อนคำสั่งระบบมาตรฐานและรับความปลอดภัยสุทธิ ต้องการ

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

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

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

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

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


54
"ทำไมมันถึงเป็นเช่นนี้" "เพราะมาตรฐานพูดอย่างนั้น" "ทำไมมาตรฐานถึงพูดอย่างนั้น?" "เพราะมันใช้งานได้แล้วชอบสิ่งนี้"
Baptiste Candellier

16
ย่อหน้าสุดท้ายคือเหตุผลที่แท้จริง กล่องโต้ตอบการยืนยันและ " คุณต้องการทำสิ่งนี้จริง ๆ หรือไม่? " ข้อความแจ้งนั้นใช้สำหรับ wimps :-)
TripeHound

@BaptisteCandellier - เห็นด้วย มันเป็นเหตุผลที่ดีที่สุดออกมี แต่ยั่วเย้าเพียงออกจากการเข้าถึงคำตอบนี้
TED

2
ย่อหน้าสุดท้ายคือเหตุผลที่ว่าทำไมถึงrm -rfมีประสิทธิภาพถึงแม้ว่าคุณจะไม่ได้ตั้งใจที่จะเรียกใช้ในโฮมได

2
@TED ​​ตลกว่าไม่มีใครพูดถึงว่าunlink (2) syscallยัง 'ล้มเหลว' เพื่อถาม“ แม่ฉันขอได้ไหม?”เพื่อยืนยันเมื่อใดก็ตามที่มีการพูดคุยแบบเซมิเทิลนัลหลังศีรษะอันโอชะของพวกเขา :)
tchrist

20

cpมาจากจุดเริ่มต้นของ Unix มันอยู่ที่นั่นก่อนที่จะเขียนมาตรฐาน Posix อันที่จริง: Posix เพิ่งทำเป็นพฤติกรรมที่มีอยู่ของcpในเรื่องนี้

เรากำลังพูดถึง Epoch (1970-01-01) เมื่อผู้ชายเป็นผู้ชายที่แท้จริงผู้หญิงเป็นผู้หญิงจริงและมีสิ่งมีชีวิตน้อยขนยาว ... (ฉันพูดนอกเรื่อง) ในสมัยนั้นการเพิ่มรหัสพิเศษทำให้โปรแกรมใหญ่ขึ้น นั่นเป็นปัญหาแล้วเพราะคอมพิวเตอร์เครื่องแรกที่รัน Unix นั้นเป็น PDP-7 (อัปเกรดเป็น 144KB RAM!) ดังนั้นสิ่งต่างๆจึงมีขนาดเล็กมีประสิทธิภาพไม่มีคุณสมบัติด้านความปลอดภัย

ในสมัยนั้นคุณต้องรู้ว่าคุณกำลังทำอะไรอยู่เพราะคอมพิวเตอร์ไม่มีอำนาจที่จะป้องกันไม่ให้คุณทำสิ่งที่คุณเสียใจในภายหลัง

(มีการ์ตูนที่ดีโดย Zevar ค้นหา "zevar cerveaux helpe par ordinateur" เพื่อค้นหาวิวัฒนาการของคอมพิวเตอร์หรือลองhttp://perinet.blogspirit.com/archive/2012/02/12/zevar-et- cointe.htmlตราบเท่าที่มีอยู่)

สำหรับผู้ที่สนใจจริงๆ (ฉันเห็นการเก็งกำไรในความคิดเห็น): ต้นฉบับcpบน Unix แรกคือโค้ดแอสเซมเบลอร์ประมาณสองหน้า (C มาในภายหลัง) ส่วนที่เกี่ยวข้องคือ:

sys open; name1: 0; 0   " Open the input file
spa
  jmp error         " File open error
lac o17         " Why load 15 (017) into AC?
sys creat; name2: 0     " Create the output file
spa
  jmp error         " File create error

(ดังนั้นยากsys creat)

และในขณะที่เราอยู่ที่นั่น: เวอร์ชัน 2 ของ Unix ที่ใช้ (โค้ด sniplet)

mode = buf[2] & 037;
if((fnew = creat(argv[2],mode)) < 0){
    stat(argv[2], buf);

ซึ่งเป็นเรื่องยากcreatโดยไม่ต้องทดสอบหรือป้องกัน โปรดทราบว่ารหัส C สำหรับ V2 Unix cpน้อยกว่า 55 บรรทัด!


5
เกือบจะถูกต้อง excepr มันคือ "สัตว์ตัวเล็ก ๆ " (สิ่งมีชีวิตจาก Alpha Centauri) ไม่ใช่ "สัตว์ตัวน้อย "!
TripeHound

1
@TED: มันเป็นไปได้ทั้งหมดในรุ่นแรกของcpเพียงแค่opened ปลายทางด้วยO_CREAT | O_TRUNCและดำเนินการread/ writeวง; แน่นอนว่าด้วยความทันสมัยcpมีลูกบิดมากมายที่โดยทั่วไปต้องพยายามไปstatยังปลายทางล่วงหน้าและสามารถตรวจสอบการมีอยู่ของมันได้อย่างง่ายดายก่อน (และใช้กับcp -i/ cp -n) แต่ถ้าความคาดหวังได้รับการยอมรับจากcpเครื่องมือกระดูกดั้งเดิมที่เปลือยเปล่าจะทำลายสคริปต์ที่มีอยู่โดยไม่จำเป็น มันไม่เหมือนกับเชลล์สมัยใหม่ที่aliasไม่สามารถใช้cp -iเป็นค่าเริ่มต้นสำหรับการใช้งานแบบโต้ตอบได้
ShadowRanger

@ShadowRanger - อืมม คุณค่อนข้างถูกที่ฉันไม่รู้จริง ๆ ว่ามันง่ายหรือยากที่จะทำ ลบความคิดเห็นแล้ว
TED

1
@ShadowRanger ใช่แล้วมันแค่ผลักบทเรียนอย่างหนักไปตามถนนจนกว่ามันจะอยู่ในระบบการผลิต ...
chrylis -on strike-

1
@sourcejedi: สนุก! ไม่เปลี่ยนทฤษฎีพื้นฐานของฉัน (ซึ่งง่ายกว่าที่จะเปิดโดยไม่มีเงื่อนไขด้วยการตัดทอนและcreatจะเทียบเท่ากับopen+ O_CREAT | O_TRUNC) แต่การขาดO_EXCLอธิบายว่าทำไมมันจึงไม่ง่ายต่อการจัดการไฟล์ที่มีอยู่ พยายามที่จะทำเช่นนั้นจะมีชีวิตชีวาโดยเนื้อแท้ (โดยทั่วไปคุณจะต้องopen/ statเพื่อตรวจสอบการมีอยู่แล้วใช้creatแต่ในระบบที่ใช้ร่วมกันขนาดใหญ่มันเป็นไปได้เสมอตามเวลาที่คุณได้รับcreatคนอื่นทำไฟล์และตอนนี้คุณปลิว มันออกไป) อาจเช่นกันเพียงเขียนทับโดยไม่มีเงื่อนไข
ShadowRanger

19

เนื่องจากคำสั่งเหล่านี้มีไว้เพื่อใช้ในสคริปต์อาจทำงานได้โดยไม่ต้องมีการกำกับดูแลของมนุษย์และเนื่องจากมีหลายกรณีที่คุณต้องการเขียนทับเป้าหมายอย่างแน่นอน (ปรัชญาของ Linux shell คือมนุษย์รู้ว่าอะไร s / เขากำลังทำ)

ยังมีการป้องกันบางประการ:

  • GNU cpมี-n| --no-clobberตัวเลือก
  • หากคุณคัดลอกหลายไฟล์ไปยังไฟล์เดียวcpจะบ่นว่าไฟล์ล่าสุดไม่ใช่ไดเรกทอรี

สิ่งนี้ใช้กับการใช้งานเฉพาะผู้ขายและคำถามไม่ได้เกี่ยวกับการใช้งานเฉพาะของผู้จัดจำหน่าย
schily

10

มันเป็น "ทำสิ่งหนึ่งในครั้งเดียว"?

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

บางครั้งเรามีคำอธิบายสำหรับตัวเลือกการออกแบบดั้งเดิมเนื่องจากนักพัฒนาได้เขียนเกี่ยวกับพวกเขา แต่ฉันไม่มีคำตอบที่ดีสำหรับคำถามนี้

เหตุใดจึงcpออกแบบวิธีนี้

ปัญหาคือ Unix อายุมากกว่า 40 ปี

หากคุณกำลังสร้างระบบใหม่ตอนนี้คุณอาจเลือกการออกแบบที่แตกต่างกัน แต่การเปลี่ยนยูนิกซ์จะทำลายสคริปต์ที่มีอยู่ดังที่กล่าวไว้ในคำตอบอื่น ๆ

ทำไมถูก cpออกแบบมาเพื่อเขียนทับไฟล์ที่มีอยู่ในใจ

คำตอบสั้น ๆ คือ "ฉันไม่รู้" :-)

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

$ cat first.html > second.html

second.htmlคำสั่งนี้ยังเขียนทับเงียบ

ฉันสนใจที่จะคิดว่าโปรแกรมเหล่านี้สามารถออกแบบใหม่ได้อย่างไร มันอาจต้องมีความซับซ้อนเป็นพิเศษ

ผมคิดว่านี่เป็นส่วนหนึ่งของคำอธิบาย: ต้น Unix เน้นเรียบง่ายใช้งาน สำหรับคำอธิบายโดยละเอียดเพิ่มเติมโปรดดู "แย่กว่าดีกว่า" เชื่อมโยงท้ายคำตอบนี้

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

ผู้ใช้สามารถเรียกใช้rm second.htmlก่อนถ้าเธอต้องการ นี่อาจเป็นการประนีประนอมที่ดี! มันมีข้อเสียที่เป็นไปได้บางอย่างของมันเอง

  1. ผู้ใช้จะต้องพิมพ์ชื่อไฟล์สองครั้ง
  2. rmคนยังได้รับในเปลืองใจใช้ ดังนั้นฉันต้องการทำให้rmปลอดภัยยิ่งขึ้นเช่นกัน แต่อย่างไร หากเราrmแสดงแต่ละชื่อไฟล์และขอให้ผู้ใช้ยืนยันตอนนี้เธอต้องเขียนสามบรรทัดคำสั่งแทนที่จะเป็นหนึ่ง นอกจากนี้หากเธอต้องทำเช่นนี้บ่อยเกินไปเธอจะติดนิสัยและพิมพ์ "y" เพื่อยืนยันโดยไม่คิด ดังนั้นมันอาจจะน่ารำคาญมากและมันก็ยังอาจเป็นอันตรายได้

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

ฉันคิดว่ามันเป็นสิ่งสำคัญเช่นกันที่จะเข้าใจข้อ จำกัด ของฮาร์ดแวร์ Unix ดั้งเดิม - RAM ที่ จำกัด และพื้นที่ดิสก์เอาต์พุตที่แสดงบนเครื่องพิมพ์ที่ช้า รวมถึงซอฟต์แวร์ระบบและการพัฒนา

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

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

การใช้> second.htmlเป็นบิตเช่นการใช้คำสั่งในตัวแก้ไขบรรทัด ผลที่ได้ขึ้นอยู่กับสถานะปัจจุบัน (หากsecond.htmlมีอยู่แล้วเนื้อหาจะถูกยกเลิก) หากผู้ใช้ไม่แน่ใจเกี่ยวกับสถานะปัจจุบันเธอคาดว่าจะเรียกใช้lsหรือls second.htmlก่อน

"ใช้งานง่าย" เป็นหลักการออกแบบ

มีการตีความที่เป็นที่นิยมของการออกแบบ Unix ซึ่งเริ่มต้น:

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

...

กาเบรียลแย้งว่า "แย่กว่าดีกว่า" ผลิตซอฟต์แวร์ที่ประสบความสำเร็จมากกว่าวิธีการของ MIT: ตราบใดที่โปรแกรมเริ่มต้นดีโดยทั่วไปมันจะใช้เวลาและความพยายามน้อยกว่าในการเริ่มต้นและจะปรับตัวเข้ากับสถานการณ์ใหม่ได้ง่ายขึ้น ยกตัวอย่างเช่นการย้ายซอฟต์แวร์ไปยังเครื่องใหม่ทำได้ง่ายขึ้นด้วยวิธีนี้ ดังนั้นการใช้งานจะแพร่กระจายอย่างรวดเร็วนานก่อนที่โปรแกรม [ดีกว่า] จะมีโอกาสได้รับการพัฒนาและนำไปใช้ (ข้อได้เปรียบผู้เสนอญัตติแรก)

https://en.wikipedia.org/wiki/Worse_is_better


เหตุใดจึงเขียนทับเป้าหมายด้วยcp"ปัญหา" การขออนุญาตแบบโต้ตอบหรืออาจล้มเหลวอาจเป็นปัญหาใหญ่
Kusalananda

ว้าวขอบคุณ. เสริมแนวทาง: 1) เขียนโปรแกรมที่ทำสิ่งหนึ่งและทำได้ดี 2) เชื่อถือโปรแกรมเมอร์
พีชคณิต

2
@ Kusalananda การสูญเสียข้อมูลเป็นปัญหา ฉันเองสนใจลดความเสี่ยงที่จะสูญเสียข้อมูล มีหลายวิธีในการนี้ การบอกว่ามันเป็นปัญหาไม่ได้หมายความว่าทางเลือกไม่มีปัญหา
sourcejedi

1
@riderdragon โปรแกรมที่เขียนด้วยภาษา C มักจะล้มเหลวในรูปแบบที่น่าประหลาดใจมากเพราะ C ไว้วางใจโปรแกรมเมอร์ แต่โปรแกรมเมอร์ไม่น่าเชื่อถือ เราต้องเขียนเครื่องมือขั้นสูงเช่น valgrindซึ่งจำเป็นต้องลองและค้นหาข้อผิดพลาดที่โปรแกรมเมอร์ทำ ฉันคิดว่ามันสำคัญที่จะต้องมีภาษาโปรแกรมอย่าง Rust หรือ Python หรือ C # ที่พยายามบังคับใช้ "ความปลอดภัยของหน่วยความจำ" โดยไม่ต้องเชื่อใจโปรแกรมเมอร์ (ภาษา C ถูกสร้างโดยหนึ่งในผู้เขียน UNIX เพื่อเขียน UNIX ในภาษาพกพา)
sourcejedi

1
ดียิ่งขึ้นคือcat first.html second.html > first.htmlจะให้ผลลัพธ์ในfirst.htmlการเขียนทับด้วยเนื้อหาของsecond.htmlเท่านั้น เนื้อหาต้นฉบับหายไปตลอดเวลา
Doneal24

9

การออกแบบ "cp" กลับไปสู่การออกแบบดั้งเดิมของ Unix มีในความเป็นจริงเป็นปรัชญาที่สอดคล้องกันที่อยู่เบื้องหลังการออกแบบระบบปฏิบัติการยูนิกซ์ซึ่งได้รับน้อยว่าครึ่งหนึ่งติดตลกถูกเรียกว่าเลว-is-ดีกว่า *

แนวคิดพื้นฐานคือการทำให้รหัสง่าย ๆ คือการพิจารณาการออกแบบที่สำคัญยิ่งกว่าที่มีส่วนต่อประสานที่สมบูรณ์แบบหรือ "ทำสิ่งที่ถูกต้อง"

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

  • ความถูกต้อง - การออกแบบจะต้องถูกต้องในทุกด้านที่สังเกตได้ มันจะดีกว่าเล็กน้อยที่จะง่ายกว่าที่ถูกต้อง

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

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

( เน้นที่เหมือง )

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

สำหรับเหตุผลที่ว่าทำไมระบบปฏิบัติการที่มีวิธีการออกแบบนั้นเกิดขึ้นเป็นระบบที่ได้รับรางวัลมากกว่าระบบปฏิบัติการอื่น ๆ ทั้งหมดที่ถูกสร้างขึ้นในเวลานั้นผู้เขียนบทความนี้ก็มีทฤษฎีเช่นกัน

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

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

* - หรือสิ่งที่ผู้เขียน แต่ไม่มีใครเรียกว่า "วิธีการที่รัฐนิวเจอร์ซีย์"


1
นี่คือคำตอบที่ถูกต้อง
tchrist

+1 แต่ฉันคิดว่ามันจะช่วยให้มีตัวอย่างที่เป็นรูปธรรม เมื่อคุณติดตั้งเวอร์ชันใหม่ของโปรแกรมที่คุณแก้ไขและรวบรวมใหม่ (และอาจผ่านการทดสอบ :-) คุณต้องการเขียนทับโปรแกรมรุ่นเก่าโดยเจตนา (และคุณอาจต้องการพฤติกรรมที่คล้ายกันจากคอมไพเลอร์ของคุณ. ดังนั้นในช่วงต้น UNIX มีเพียงcreat()VS open(). open()ไม่สามารถสร้างไฟล์ถ้ามันไม่ได้อยู่. มันใช้เวลาเพียง 0/1/2 สำหรับการอ่าน / เขียน / ทั้งสอง. มันยังไม่ได้ใช้O_CREAT, และไม่มีO_EXCL)
sourcejedi

@sourcejedi - ขออภัย แต่ในฐานะนักพัฒนาซอฟต์แวร์ตัวเองฉันไม่สามารถนึกถึงสถานการณ์อื่นได้มากกว่าที่ฉันทำสำเนา :-)
TED

@TED ​​ขอโทษฉันหมายถึงฉันขอแนะนำตัวอย่างนี้เป็นหนึ่งในกรณีที่ไม่เกิดขึ้นได้ยากที่คุณต้องการเขียนทับอย่างแน่นอนเทียบกับการเปรียบเทียบคำถามที่คุณอาจไม่ได้
sourcejedi

0

เหตุผลหลักคือGUI เป็นคำจำกัดความแบบโต้ตอบในขณะที่ไบนารี like /bin/cpเป็นเพียงโปรแกรมที่สามารถเรียกได้จากทุกสถานที่ตัวอย่างเช่นจาก GUI ของคุณ ;-) ฉันพนันได้เลยว่าทุกวันนี้ผู้คนส่วนใหญ่ที่โทรหา/bin/cpจะไม่ได้มาจากเทอร์มินัลจริงกับผู้ใช้ที่พิมพ์คำสั่งเชลล์ แต่แทนที่จะมาจากเซิร์ฟเวอร์ HTTP หรือระบบเมลหรือ NAS การป้องกันในตัวจากข้อผิดพลาดของผู้ใช้ทำให้รู้สึกสมบูรณ์ในสภาพแวดล้อมแบบโต้ตอบ น้อยลงดังนั้นในไบนารีที่เรียบง่าย ตัวอย่างเช่น GUI ของคุณมักจะโทรมา/bin/cpที่พื้นหลังเพื่อดำเนินการจริงและจะต้องจัดการกับคำถามเพื่อความปลอดภัยตามมาตรฐานแม้ว่าจะเพิ่งถามผู้ใช้!

โปรดทราบว่าตั้งแต่วันแรกไปจนถึงเรื่องไม่สำคัญที่จะเขียนเสื้อคลุมที่ปลอดภัยรอบ ๆ/bin/cpหากต้องการ ปรัชญา * nix คือการจัดเตรียมการบล็อกแบบง่ายสำหรับผู้ใช้: สิ่งเหล่านี้/bin/cpคือสิ่งหนึ่ง

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