สัญลักษณ์แปลก ๆ นี้“:>” ใน bash หมายถึงอะไร


47

ฉันพบบางสิ่งในสคริปต์ แต่ไม่ได้เป็นของสคริปต์หลัก มีอยู่:>ในแถว

คุณช่วยอธิบายความหมายของฉันให้ฉันได้ไหม

:> file
while read A B C D E; do echo "$A;$B;$D;$E;$C" >> file; done < otherfile

6
ที่สำคัญ:>ไม่ใช่ตัวดำเนินการเดียว อาจเข้าใจได้ง่ายกว่าถ้าคุณอ่าน: > fileแทน
jpfx1342

หมายความว่าผู้ที่เขียนสคริปต์ควรเปลี่ยนเส้นทางเอาต์พุตของลูปไปที่ไฟล์: while read A B C D E; do echo "$A;$B;$D;$E;$C"; done < otherfile > file. หรือดีกว่านั้นพวกเขาควรใช้เครื่องมือที่เหมาะสมสำหรับงาน awk ตามที่ Peterแนะนำ เช่นกันที่คุณมักจะต้องการที่จะใช้-rreadสวิทช์ด้วย
Tom Fenech

นอกทุบตีมันจะเป็นรอยยิ้มสำหรับอีกา
smci

คำตอบ:


46

มี:> ในบรรทัดของสคริปต์ทุบตี มันหมายความว่าอะไร?

:> file

มันเป็นวิธีที่สั้น ๆ ในการพูดว่า:

  • หากfileไม่มีอยู่ให้สร้างขึ้นใหม่ให้ตัดทอนเป็น0ไบต์

ซึ่งหมายความว่าคุณมั่นใจได้ว่าfileมีอยู่จริงและว่างเปล่า

คุณยังสามารถใช้> fileแต่:> fileพกพาได้มากกว่า

ดูคำถาม Stack Overflow จุดประสงค์ของ ':' (โคลอน) GNU Bash Builtin คืออะไร สำหรับข้อมูลเพิ่มเติม.


ฉันไม่เข้าใจบรรทัดที่สอง ฉันคิดว่าการอ่านตัวแปรอ่าน คำสั่งก้องก็แปลกเช่นกัน คุณอธิบายได้ไหม
diego9403

ฉันไม่ได้เป็นผู้เชี่ยวชาญ Unix แต่ฉันคิดว่าบรรทัดที่สองอ่านสิ่งที่มาจากotherfileและechos fileพวกเขาออกไป นอกจากนี้ยังทำให้ตัวแปรจากสิ่งที่อ่าน ... หากคุณต้องการคำตอบที่ชัดเจนโปรดถามคำถามของคุณเอง
DavidPostill

2
@ diego9403: readรับอินพุตจาก stdin ด้วยตัวเองมันจะอ่านสิ่งที่คุณพิมพ์ เนื่องจาก stdin ถูกเปลี่ยนเส้นทางไป<otherfileแล้วเนื้อหาของotherfileคือ "พิมพ์" ลงใน stdin ดังนั้นreadรับค่าบรรทัดโดยบรรทัดเป็นตัวแปร $ A, $ B, $ C, $ D และ $ E
slebetman

ดังนั้นจึงเป็นเพียงทางเลือกที่ชัดเจนกว่าtruncateจาก coreutils?
Federico Poloni

1
@PeterCordes ฉันไม่ได้หมายถึง "คลุมเครือ" เช่นเดียวกับใน "มันผิดปกติ" แต่ใน "มันชัดเจนน้อยลงสำหรับผู้อ่าน"
Federico Poloni

29

ดูเหมือนจะเป็นวิธีที่แปลกใหม่ในการสร้างไฟล์ใหม่ ในbash :เป็นคำสั่ง null:

$ type : 
: is a shell builtin 
$ help : 
:: :
    Null command.

    No effect; the command does nothing.

    Exit Status:
    Always succeeds.

>เปลี่ยนเส้นทางการส่งออกของ:ไปยังไฟล์


2
มันจะตัดทอนไฟล์ถ้ามันมีอยู่แล้ว ...
DavidPostill

2
ใช่นี่คือสิ่งที่>ทำ
Arkadiusz Drabczyk

2
:trueเป็นชวเลข อาจเป็นได้ในหอยบางtrueตัว ทั้งสองถูกสร้างขึ้นในทุบตี
ปีเตอร์กอร์เดส

12

:trueเป็นชื่ออีก ทั้งสองมีความ builtins เปลือกทุบตี แต่ไม่มีเพียง/bin/: /bin/trueการเปลี่ยนเส้นทางขาออกทำให้เกิดเปลือกเพื่อไฟล์ด้วยopen(2) O_CREAT|O_TRUNCหากไม่มีการเขียนอะไรมันจะอยู่ที่ความยาวเป็นศูนย์

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


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

บรรทัดที่ 2 เป็นลูปที่อ่านบรรทัดจากotherfileลงในตัวแปรที่ตั้งชื่อบางตัว ร่างกายวนใช้echoพิมพ์ด้วย;ตัวคั่นแทนสิ่งที่พวกเขาเคยมีมาก่อนช่องว่าง fileถูกปิดและเปิดใหม่ (สำหรับผนวก) แต่ละการวนซ้ำเนื่องจากการเปลี่ยนเส้นทางอยู่ในลูป การใช้while ...;do read -r ...;done <otherfile >fileจะดูดน้อยลงและหลีกเลี่ยงความต้องการตัดทอนไฟล์ก่อน read -rไม่กิน\เป็นตัวหนี

การประมวลผลข้อความใน bash ค่อนข้างช้า ส่วนหนึ่งที่หลีกเลี่ยงไม่ได้: readต้องไปทีละหนึ่งไบต์ (การread(2)เรียกระบบหนึ่งครั้งต่อไบต์) เพื่อหลีกเลี่ยงการแก้ไขปัญหาการสิ้นสุดของบรรทัด มันจะเป็นการดีกว่าถ้าใช้เครื่องมือที่เหมาะสมสำหรับงาน:

awk -vOFS=';' '{ print $1, $2, $4, $5, $3 }' -- otherfile  >file

--หมายความว่าสคริปต์ของคุณจะไม่ผิดเพี้ยนถ้าotherfileตั้งชื่ออย่างโง่--version

การตั้งค่าตัวคั่นฟิลด์เอาต์พุตเป็น;หมายความว่าคุณสามารถส่งผ่านหลาย ๆ ฟิลด์ตามที่ต้องการพิมพ์ได้ เชลล์readกำหนดส่วนที่เหลือทั้งหมดของบรรทัดด้วยช่องว่างให้กับตัวแปรสุดท้าย แต่ไม่มีวิธีที่จะบอก awk ให้แยกออกเป็น 5 เท่านั้นถ้านั่นเป็นสิ่งสำคัญ Perl ทำให้การดำเนินการนี้เป็นเรื่องง่ายเนื่องจากsplitสามารถใช้เขตข้อมูลสูงสุดได้ แต่จะช้ากว่าการเริ่มต้น awk มาก

จริงๆแล้วมันกลายเป็นว่าไม่ยากเพียง regex น่าเกลียดที่จะเขียน ในการรับส่วนที่เหลือของสายแทนที่จะเป็น$5awk การวนลูปเหนือฟิลด์ยังคงสูญเสียช่องว่างดั้งเดิม แนวคิดที่ทำงานได้เป็นครั้งแรกของฉันคือการใช้gensubบน$0(ทั้งบรรทัด) เพื่อลบ 4 ฟิลด์แรก (เช่นที่ไม่ใช่ช่องว่างตามด้วยช่องว่าง) ออกจากทุกอย่างอื่น:

awk -vOFS=';' '{ tail = gensub("[[:space:]]*([^[:space:]]+[[:space:]]+){4}", "", 1); print $1, $2, $4, tail, $3 }' -- otherfile >file

ฉันเข้าใจถูกในการลองครั้งแรก แต่ความจริงที่ว่าฉันรู้สึกประทับใจกับตัวเองเพราะมันบอกอะไรบางอย่างเกี่ยวกับความสามารถในการอ่านของรหัส awk นั้น >. <

หมายเหตุว่ามันเหมือนprintเป็นมาก่อน แต่มีในสถานที่ของtail$5

echo 'A  B c DD    e      f g    f' | 
  awk -vOFS=\; '{ tail = gensub("[[:space:]]*([^[:space:]]+[[:space:]]+){4}", "", 1);
   print $1, $2, $4, tail, $3 }'

A;B;DD;e       f g    f;c

มันจะน่าประทับใจมากขึ้นถ้าฉันสามารถคัดลอก / วางตัวอักษรและแสดงว่ามันผ่านมาในการส่งออก พิมพ์หนึ่งใน bash ด้วย ^ Q ctrl-Q หมายถึงการกดปุ่มกดถัดไปเป็นตัวอักษรเนื่องจากการแก้ไขเส้นสไตล์ emacs ของ bash นั้นเหมือนกับ emacs จริงสำหรับสิ่งนี้

http://mywiki.wooledge.org/BashFAQมีบางสิ่งที่มีประโยชน์เกี่ยวกับการเขียนสคริปต์ในรูปแบบที่จะไม่ทำลายไม่ว่าคุณจะใส่ข้อมูลหรือชื่อไฟล์ใดในสคริปต์

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