`>` และ `>> ทำงานอย่างไร


9

ฉันพยายามrevไฟล์แล้วก็ไพพ์ไปcat > same_fileแต่มันเปลี่ยนเป็นไฟล์เปล่า

ในขณะที่ฉันพยายามrev file.txt | cat > file2.txt && mv file.txt file2.txt;มันทำงาน

แม้rev file.txt | cat >> file.txt;ทำงาน

แต่เมื่อฉันลองrev file.txt | cat > file.txtมันก็ล้มเหลว


นอกจากนี้คุณยังสามารถปล่อยออกมาเช่นนี้cat rev file.txt > file2.txt && mv file2.txt file.txtนี่คือการใช้ฟุ่มเฟือยของ catโดยปล่อยให้คุณพล่านวางกระบวนการพิเศษ
matega

คำตอบ:


19

สิ่งพื้นฐานที่คุณต้องเข้าใจในกรณีนี้ระหว่างการเปลี่ยนเส้นทางทั้งสองวิธี (> และ >>) คือ:

>

เปลี่ยนเส้นทางและเขียนทับข้อมูลที่ชี้ไป สิ่งนี้เกิดขึ้นขณะรับข้อมูลใด ๆ ผ่านทางท่อ "|"

>>

เปลี่ยนเส้นทางและต่อข้อมูลที่ชี้ไป สิ่งนี้เกิดขึ้นขณะรับข้อมูลใด ๆ ผ่านทางท่อ "|"

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

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

rev file.txt | cat > file.txt

สิ่งที่เกิดขึ้นจริงใน "คำอธิบายการเคลื่อนไหวช้า" คือ:

  1. revเตรียมที่จะกลับเนื้อหาของfile.txtและส่งไปยังไปป์
  2. ในขณะที่จะส่งข้อมูลไปยังท่อท่อลำธารโดยตรงไปยังrevcat
  3. ในขณะที่catกำลังรับข้อมูลมันจะนำไปใช้โดยอัตโนมัติกับfile.txtมันถูกตั้งค่าด้วย
  4. คำหลักที่นี่คือ "ในขณะที่" เพราะทุกอย่างเกิดขึ้นในเวลาเดียวกัน โปรดดูความคิดเห็นที่ยอดเยี่ยมด้านล่างโดย Emil เพื่อทำความเข้าใจอย่างลึกซึ้งในส่วนนี้
  5. catจะไม่รอrevไปป์ที่ไฟล์ทั้งหมด file.txtมันก็จะเริ่มต้นนาทีส่วนแรกของข้อมูลที่ได้รับไปซึ่งหมายถึงขึ้นอยู่กับสิ่งที่สัญลักษณ์ที่คุณใช้ก็จะเปิดการเชื่อมต่อกับ
  6. ในกรณีนี้เนื่องจากคุณใช้>แทน>>เชลล์จะตัดทอนไฟล์เอาท์พุทซึ่งหมายความว่ามันจะเปิดและล้างข้อมูลfile.txtในขณะที่รอข้อมูลใหม่เพื่อเข้าใช้ ด้วย>>มันจะเปิดการเชื่อมต่อด้วยfile.txtและรอข้อมูลใหม่ในบรรทัดสุดท้ายที่ตรวจพบ
  7. เนื่องจากข้อมูลที่ถูกลบแล้วในfile.txtด้วย> , revจะพยายามที่จะทำผลงานของมันและได้รับอะไรเพราะcatถูกลบทุกอย่างในการเตรียมการสำหรับข้อมูลใหม่

แล้วทำไมคนอื่นถึงทำงานหลังจากอ่านข้อความข้างต้น ด้วยเหตุนี้:

rev file.txt | cat > file2.txt && mv file.txt file2.txt

ที่นี่คุณกำลังส่งไปยังแมวซึ่งกำลังส่งข้อมูลไปยังไฟล์อื่น ในกรณีนี้แฟ้มใส่ประมวลผลไม่ได้เป็นเช่นเดียวกับไฟล์ที่ส่งออกfile.txt file2.txtหลังจากนั้นคุณจะเขียนทับทั้งหมดfile2.txtด้วยfile.txtดังนั้นกระบวนการทั้งหมดที่ทำโดยcatถูกลบ โดยพื้นฐานแล้วทั้งบรรทัดสามารถทำให้ง่ายขึ้นเช่นcp file.txt file2.txtเพราะมันทำสิ่งเดียวกันตั้งแต่file2.txtในตอนท้ายสูญเสียrevและถูกเขียนทับด้วยmvคำสั่ง

rev file.txt | cat >> file.txt

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


5
ไฟล์ไม่ถูกตัดทอนโดย cat มันถูกตัดทอนโดยเชลล์ก่อนคำสั่งใด ๆ ในไปป์ไลน์จะเริ่มต้นขึ้น
Emil Jeřábek

ถูกต้องกำลังมองหาคำที่ง่ายต่อการอธิบาย เนื่องจากเป็นการยากที่จะอธิบายว่า OP ไม่ทราบว่ามันคืออะไรและทุกอย่างนั้น พยายามทำให้มันเป็น "มิตร" ที่สุด
Luis Alvarado

1
ไม่สำคัญว่ามันทำโดยเปลือก แต่เวลาที่คุณนำเสนอนั้นผิด การตัดจะไม่เกิดขึ้นในขั้นตอนที่ 6 แต่ในขั้นตอนที่ 0 rev file.txt | cat --bogus-option > file.txtจะตัดทอนไฟล์แม้ว่าแมวจะไม่พยายามเปิด
Emil Jeřábek

@ EmilJeřábekคุณถูกต้อง ผู้ใช้ที่ยังไม่รู้ว่ามันจะทำงานได้ง่ายขึ้นถ้าเราไปทีละขั้นตอนด้วยคำสั่งเท่านั้น ตัวอย่างของคุณยังคงส่งข้อมูลไปยังไฟล์เดียวกันดังนั้นทุบตีจะอ่านทั้งบรรทัดนั้นดูผลลัพธ์และยังคงเปิดและตัดทอน ข้อผิดพลาดเป็นเพียง stderr ส่งออกไปยัง stdout
Luis Alvarado

4
ดูเพิ่มเติมututilsชุดเครื่องมือที่ยอดเยี่ยม (หาได้จากที่เก็บของแพ็คเกจmoreutils) ซึ่งรวมถึงspongeเครื่องมือที่ออกแบบมาเป็นพิเศษสำหรับใช้ในการเขียนทับไฟล์อินพุต ยกตัวอย่างเช่นrev file.txt >file2.txt && mv file2.txt file.txtการแก้ปัญหาจะกลายเป็นซึ่งจะทำงานอย่างถูกต้องแม้จะมีบางสิ่งบางอย่างที่มีชื่ออยู่แล้วrev file.txt | sponge file.txt file2.txt
Daniel Wagner

9

เมื่อเชลล์เห็นการเปลี่ยนเส้นทางมันจะเปิดไฟล์ที่เกี่ยวข้องก่อนที่จะดำเนินการคำสั่งใด ๆ ที่เกี่ยวข้อง ดังนั้นเมื่อคุณ:

foo file.txt | bar > file.txt

การเปลี่ยนเส้นทางที่จะfile.txtทำให้มันถูกตัดทอนก่อนที่จะ fooถูกเรียกใช้และสามารถอ่านfile.txtได้ ในหมายเหตุด้านนี่คือเหตุผลที่คุณไม่สามารถทำ:

sed 'blah' file.txt > file.txt

และทำไมsedมีตัวเลือกการแก้ไขในสถานที่

สุดท้ายทำ:

.. | cat > file.txt

คือการใช้แมวที่ไร้ประโยชน์โดยเฉพาะอย่างยิ่งถ้าคุณพยายามอ่านจากfile.txtก่อนหน้า

หากคุณต้องการที่จะย้อนกลับไฟล์ในสถานที่ที่มีทางลัดไม่มี คุณอาจจะสามารถใช้sedหรือawkลูกเล่นกับการแก้ไขในสถานที่


3

>เป็นตัวเปลี่ยนเส้นทาง (โอเปอเรเตอร์) ส่งเอาต์พุตไปยังสิ่งอื่น
(อินพุตของคำสั่งถัดไปเครื่องพิมพ์ .. )

ในกรณีของคุณเอาต์พุตไปที่ไฟล์file.txtหากไฟล์นี้มีอยู่แล้วไฟล์นั้นจะถูกเขียนทับหากไม่ได้สร้างขึ้น

>>เป็นตัวดำเนินการผนวกหากfile.txtมีอยู่แล้วเอาต์พุตจะถูกผนวกเข้ากับท้ายไฟล์ หากไฟล์ไม่มีอยู่ไฟล์จะถูกสร้างขึ้นและเอาต์พุตที่เขียนลงในไฟล์ใหม่เช่นเดียวกับ>(ตัวเปลี่ยนเส้นทาง)


OP ดูเหมือนจะเข้าใจสิ่งนี้แล้ว ความสับสนดูเหมือนว่าเกิดจากไฟล์เดียวกันที่อยู่บนทั้งสองด้านของตัวดำเนินการ>และ>>ตัวดำเนินการ
bzlm

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