การเปลี่ยนเส้นทาง stdout และ stderr ไปยังไฟล์เดียวกันนั้นปลอดภัยหรือไม่โดยไม่มีการคัดลอกไฟล์ descriptor?


27

ฉันเริ่มต้นในไดเรกทอรีว่างเปล่า

$ touch aFile
$ ls
aFile

จากนั้นฉันก็lsโต้เถียงกันสองข้อข้อหนึ่งข้อหนึ่งไม่ได้อยู่ในไดเรกทอรีนี้ outputฉันเปลี่ยนเส้นทางทั้งลำธารส่งออกไปยังไฟล์ชื่อ ฉันใช้>>เพื่อหลีกเลี่ยงการเขียนพร้อมกัน

$ ls aFile not_exist >>output 2>>output
$ cat output
ls: cannot access 'not_exist': No such file or directory
aFile

ซึ่งดูเหมือนว่าจะทำงาน มีอันตรายกับวิธีนี้หรือไม่?


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

ทำไมคุณไม่ใช้มาตรฐานที่มากกว่าls aFile not_exist &>>outputนี้? (หมายเหตุฉันสมมติว่าคุณกำลังใช้bash )
FedonKadifeli

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

1
@FedonKadifeli &>>ไม่ได้เป็นมาตรฐาน มันคือ DEPRECATED, ไวยากรณ์ที่คลุมเครือซึ่งทำงานแตกต่างกันไปในแต่ละเชลล์ ฉันสงสัยว่าพวกคุณได้รับของจากไหน
ลุงบิลลี่

4
ทุบตีไม่ได้เป็นมาตรฐาน เอกสารมาตรฐาน POSIX ว่าls &>>foo ...ควรจะแยกวิเคราะห์เป็นสอง comands ls &และ>>foo ...และนี่คือวิธีการที่เปลือกหอยอื่น ๆ เช่น/bin/shจากอูบุนตูจะแยกมัน เพราะมันเลิกใช้แล้วคุณสามารถดูได้ที่นี่ - แม้ว่าฉันจะไม่เสแสร้ง คุณอาจถามผู้bashดูแลหากพวกเขาพิจารณาใช้เป็นความคิดที่ดี
ลุงบิลลี่

คำตอบ:


22

>>bar 2>&1ไม่มีก็ไม่ได้เป็นเพียงเป็นที่ปลอดภัยที่เป็นมาตรฐาน

เมื่อคุณเขียน

foo >>bar 2>>bar

คุณกำลังเปิดbarไฟล์สองครั้งด้วยO_APPENDการสร้างวัตถุไฟล์อิสระอย่างสมบูรณ์สองรายการ [1] แต่ละรายการมีสถานะของตัวเอง (ตัวชี้โหมดเปิด ฯลฯ )

นี่แตกต่างอย่างมาก2>&1ซึ่งเพิ่งเรียกการเรียกของdup(2)ระบบและทำให้นามแฝงแทนกัน stderr และ stdout สำหรับวัตถุไฟล์เดียวกัน

ตอนนี้มีปัญหากับเรื่องนี้:

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

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

[1] "Open File Descriptions" ในภาษา POSIX


3
อย่างเป็นทางการสำหรับไฟล์ที่ผนวกโหมดมันมีความปลอดภัย ปัญหาที่อ้างถึงเป็นข้อบกพร่องใน NFS ที่ทำให้ไม่เหมาะสม (ไม่สอดคล้องกับ POSIX) เป็นระบบไฟล์ สำหรับกรณีที่ไม่ใช่โหมดต่อท้ายจะไม่ปลอดภัย
..

1
นั่นเป็นสาระสำคัญ การผนวกสองครั้งของ OP ไม่ปลอดภัยในการใช้ (นอกเหนือจากการไม่มีจุดหมายอย่างสมบูรณ์) และO_APPENDเป็นบอทชนิดหนึ่งอยู่แล้ว - ค่อนข้างน่าเบื่อที่จะใช้อย่างถูกต้อง
mosvy

ฉันเชื่อว่าสภาพการแข่งขัน NFS เป็นเพียงระหว่างลูกค้าที่แตกต่าง ไคลเอ็นต์ระบบปฏิบัติการควรประสานงานการเขียนทั้งหมดระหว่างกระบวนการ
Barmar

@Barmar ที่จะเป็นจริงถ้าไคลเอ็นต์ OS สนใจเฉพาะมุมมองของตัวเองของไฟล์ nfs แต่เมื่อเขียนไปยังไฟล์ nfs ที่เปิดด้วยO_APPENDไคลเอนต์จะดึงขนาด "ของจริง" ของไฟล์จากเซิร์ฟเวอร์ ("ตรวจสอบความถูกต้อง" inode) จากนั้นทำการค้นหา + เขียน + แคชปรับปรุง inode และเฉพาะส่วนสุดท้ายคือ ทำภายใต้ล็อคซึ่งหมายความว่าส่วนแรกยังคงสามารถดึงขนาดเก่าจากเซิร์ฟเวอร์และแทนที่ส่วนที่ถูกต้องจาก inode ท้องถิ่น / แคช lseek(SEEK_END)ปัญหาเดียวกันกับ
mosvy

ฉันยังไม่เห็นว่าจะทำให้เกิดสภาวะการแข่งขันระหว่างสองสตรีมในไคลเอนต์เดียวกันได้อย่างไร สตรีมทั้งสองควรอ้างอิงถึงไอโหนดในเครื่องเดียวกัน
Barmar

22

จะเกิดอะไรขึ้นเมื่อคุณทำ

some_command >>file 2>>file

คือfileจะเปิดขึ้นเพื่อผนวกสองครั้ง วิธีนี้ปลอดภัยที่จะทำบนระบบไฟล์ POSIX การเขียนใด ๆ ที่เกิดขึ้นกับไฟล์เมื่อเปิดเพื่อต่อท้ายจะเกิดขึ้นที่ส่วนท้ายของไฟล์ไม่ว่าข้อมูลนั้นจะมาในสตรีมเอาท์พุทมาตรฐานหรือสตรีมข้อผิดพลาดมาตรฐาน

สิ่งนี้ขึ้นอยู่กับการสนับสนุนสำหรับการดำเนินการเขียนต่อท้ายอะตอมในระบบไฟล์ ระบบไฟล์บางระบบเช่น NFS ไม่รองรับการผนวกอะตอมมิก ดูเช่นคำถาม"ไฟล์ผนวกอะตอมใน UNIX หรือไม่"ใน StackOverflow

การใช้

some_command >>file 2>&1

จะทำงานได้แม้ใน NFS แม้ว่า

อย่างไรก็ตามการใช้

some_command >file 2>file

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

ตัวอย่าง:

$ { echo hello; echo abc >&2; } >file 2>file
$ cat file
abc
o

helloสตริงเป็นครั้งแรกที่เขียน (ที่มีการขึ้นบรรทัดใหม่ยุติ) แล้วสตริงตามด้วยการขึ้นบรรทัดใหม่ถูกเขียนขึ้นจากความผิดพลาดมาตรฐานแทนที่abc hellผลลัพธ์คือสตริงที่abcมีการขึ้นบรรทัดใหม่แล้วตามด้วยสิ่งที่เหลืออยู่ของechoเอาต์พุตแรกoและและขึ้นบรรทัดใหม่

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

มันจะดีกว่าและปลอดภัยกว่าถ้าใช้สำนวนที่มากกว่า

some_command >file 2>&1

1
ในขณะที่เป็นจริงของเปลือกหอยที่ทันสมัย ​​แต่ก็ไม่ใช่ในเปลือก Bourne หรือ Thomson (ซึ่ง>>มาจาก) ซึ่ง>>จะเปิดให้มีการเขียนและหาที่สิ้นสุด (ฉันคิดว่าเพราะ O_APPEND ยังไม่ได้ประดิษฐ์ขึ้นมาในตอนนี้) แม้ใน Solaris 10, เอาท์พุท/bin/sh -c '(echo a; echo b >&2) >> file 2>> file; cat file' b
Stéphane Chazelas

@ StéphaneChazelasนั่นเป็นปัญหาของการติดตั้ง Solaris 10 shหรือระบบไฟล์หรือไม่?
Kusalananda

1
นั่นคือสิ่งที่>>ทำอยู่เดิมมันไม่ได้เปิดด้วย O_APPEND แต่เป็นการเปิดโดยไม่ค้นหาและจบลง มันไม่ได้เป็นปัญหามากนัก แต่มันคือสิ่งที่มันกำลังทำอยู่และถูกบันทึกไว้ให้ทำ
Stéphane Chazelas

0

มันขึ้นอยู่กับสิ่งที่คุณต้องการบรรลุ มันขึ้นอยู่กับคุณที่จะตัดสินใจว่ามันโอเคที่จะมีข้อผิดพลาดในไฟล์เดียวกับเอาท์พุท นี่เป็นเพียงการบันทึกข้อความในไฟล์ด้วยฟังก์ชันการทำงานของเชลล์ที่ให้คุณเปลี่ยนเส้นทางตามที่คุณต้องการ ไม่ว่าจะใช่หรือไม่แน่นอนทุกอย่างใน Linux สามารถทำได้หลายวิธีนี่คือวิธีของฉันในls notExistingFile existingFile >> output 2>&1 การตอบคำถาม: ในแง่ของการเปลี่ยนเส้นทางตัวเองใช่ว่าปลอดภัยอย่างสมบูรณ์


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

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