ทำไมพฤติกรรมของ `คำสั่ง 1> file.txt 2> file.txt` ต่างจาก` คำสั่ง 1> file.txt 2> & 1`


20

เมื่อคุณต้องการเปลี่ยนเส้นทางทั้ง stdout และ stderr ไปยังแฟ้มเดียวกันคุณสามารถทำมันได้โดยการใช้หรือcommand 1>file.txt 2>&1 command &>file.txtแต่ทำไมพฤติกรรมcommand 1>file.txt 2>file.txtต่างไปจากสองคำสั่งข้างต้น?

ต่อไปนี้เป็นคำสั่งการตรวจสอบ

$ cat redirect.sh
#!/bin/bash

{ echo -e "output\noutput" && echo -e "error" 1>&2; } 1>file.txt 2>&1
{ echo -e "output\noutput" && echo -e "error" 1>&2; } 1>file1.txt 2>file1.txt
{ echo -e "error" 1>&2 && echo -e "output\noutput"; } 1>file2.txt 2>file2.txt
{ echo -e "output" && echo -e "error\nerror" 1>&2; } 1>file3.txt 2>file3.txt
{ echo -e "error\nerror" 1>&2 && echo -e "output"; } 1>file4.txt 2>file4.txt

$ ./redirect.sh

$ echo "---file.txt---"; cat file.txt;\
echo "---file1.txt---"; cat file1.txt; \
echo "---file2.txt---"; cat file2.txt; \
echo "---file3.txt---"; cat file3.txt; \
echo "---file4.txt----"; cat file4.txt;
 ---file.txt---
output
output
error
---file1.txt---
error

output
---file2.txt---
output
output
---file3.txt---
error
error
---file4.txt----
output
rror

เท่าที่เห็นผลลัพธ์ดูเหมือนว่าสตริง echo ตัวที่สองจะเขียนทับ echo string ตัวแรกเมื่อคุณรันcommand 1>file.txt 2>file.txtแต่ฉันไม่รู้ว่าทำไมมันจะเกิดขึ้น (มีการอ้างอิงอยู่ที่ไหนสักแห่ง?)

คำตอบ:


43

คุณต้องรู้สองสิ่ง:

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

    การเปลี่ยนแปลงดังกล่าวจะถูกตราขึ้นโดยกระบวนการเรียกread()/ readv(), write()/ writev(), lseek()และสายระบบเช่นกัน echoคำสั่งโทรwrite()/ writev()แน่นอน

ดังนั้นสิ่งที่จะเกิดขึ้นคือ:

  • command 1>file.txt 2>&1สร้างคำอธิบายไฟล์เดียวเท่านั้นเนื่องจากเชลล์เปิดไฟล์เพียงครั้งเดียว เชลล์ทำทั้งตัวอธิบายเอาต์พุตไฟล์มาตรฐานและไฟล์ข้อผิดพลาดมาตรฐานไปที่คำอธิบายไฟล์เดียว มันทำซ้ำเอาต์พุตมาตรฐานไปยังข้อผิดพลาดมาตรฐาน ดังนั้นการเขียนผ่านตัวอธิบายไฟล์จะย้ายตำแหน่งไฟล์ปัจจุบันที่ใช้ร่วมกัน: การเขียนแต่ละครั้งจะไปหลังจากคำอธิบายไฟล์ทั่วไปที่เขียนไว้ก่อนหน้านี้ และอย่างที่คุณเห็นผลลัพธ์ของechoคำสั่งไม่ได้เขียนทับกัน
  • command 1>file.txt 2>file.txtสร้างคำอธิบายไฟล์สองคำเนื่องจากเชลล์เปิดไฟล์เดียวกันสองครั้งเพื่อตอบสนองต่อการเปลี่ยนเส้นทางทั้งสองอย่างชัดเจน เอาต์พุตมาตรฐานและตัวให้คำอธิบายไฟล์ข้อผิดพลาดมาตรฐานแม็พกับคำอธิบายไฟล์ที่แตกต่างกันสองคำสั่งจากนั้นจึงเปลี่ยนแม็พเป็นไฟล์เดียว คำอธิบายไฟล์สองไฟล์มีตำแหน่งไฟล์ปัจจุบันที่เป็นอิสระโดยสิ้นเชิงและการเขียนแต่ละครั้งจะเขียนทันทีในไฟล์รายละเอียดเดียวกัน และอย่างที่คุณเห็นผลลัพธ์คือสิ่งที่ถูกเขียนผ่านทางหนึ่งสามารถเขียนทับสิ่งที่เขียนผ่านทางอื่นในรูปแบบต่าง ๆ ตามลำดับที่คุณเรียกใช้งานการเขียน

อ่านเพิ่มเติม


1
ควรจะมีคำอธิบายเปิดแฟ้มมากกว่าคำอธิบายไฟล์ มันเป็นเรื่องของการบันทึกว่าไฟล์ถูกเปิดอย่างไรมากกว่าตัวไฟล์เอง นั่นเป็นคำศัพท์ที่ใช้โดย POSIX, Linux, Solaris และเอกสาร GNU อย่างน้อยที่สุด
Stéphane Chazelas

16

การใช้>บอกให้เขียนทับไฟล์ เนื่องจากคุณมี stdout และ stderr กำลังเขียนไปยังไฟล์ในสองการดำเนินการที่แตกต่างกันคนสุดท้ายที่จะเขียนจะเขียนทับแรก

คุณทำได้:

command 1>>file.txt 2>>file.txt

หรือ

command &>file.txt ทุบตี v4 เท่านั้นขึ้นไป

>> บอกให้ผนวกไฟล์ดังนั้นมันจะไม่แทนที่เอาต์พุตของการดำเนินการก่อนหน้า

&> เป็นวิธีที่ง่ายกว่าในการเขียน 2>&1


2
ทำไมls 1>&0และls 0>&0ยังแสดงผลลัพธ์ของ ls อยู่
Yvain

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

4
@jlmg: ไฟล์ต่อท้ายโหมดสามารถค้นหาได้ แต่การเขียนทุกครั้งจะถูกนำหน้าด้วยการค้นหาโดยนัยที่จะสิ้นสุด ไม่ว่าการแสวงหาโดยนัยนั้นคืออะตอมหรือไม่นั้นชัดเจนสำหรับฉัน
เควิน

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

1
@Kevin บนระบบไฟล์ที่สอดคล้องกับ POSIX ทั้งหมดการค้นหา O_APPEND โดยนัยคืออะตอมมิก ที่กล่าวว่าไม่ทุกระบบไฟล์ใช้ความหมายที่เกี่ยวข้องอย่างถูกต้อง - ตัวอย่างเช่น NFS (อย่างน้อย v3 และก่อนหน้า - ฉันไม่ชัดเจนใน v4) ไม่มีการสนับสนุนที่เกี่ยวข้องอบลงในโปรโตคอลลวดดังนั้นเซิร์ฟเวอร์จึงมี ไม่มีทางรู้ว่าลูกค้าเปิดไฟล์ด้วยO_APPENDหรือไม่
Charles Duffy
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.