การรันหลายคำสั่งในหนึ่งบรรทัดในเชลล์


388

บอกว่าฉันมีไฟล์/templates/appleและฉันต้องการ

  1. วางไว้ในสองที่แตกต่างกันแล้ว
  2. ลบต้นฉบับ

ดังนั้น/templates/appleจะถูกคัดลอกไปที่/templates/usedAND /templates/inuse หลังจากนั้นฉันต้องการลบต้นฉบับ

เป็นcpวิธีที่ดีที่สุดในการทำเช่นนี้ตามมาด้วยrm? หรือมีวิธีที่ดีกว่า

ฉันต้องการที่จะทำมันทั้งหมดในบรรทัดเดียวดังนั้นฉันคิดว่ามันจะมีลักษณะ:

cp /templates/apple /templates/used | cp /templates/apple /templates/inuse | rm /templates/apple

นี่เป็นไวยากรณ์ที่ถูกต้องหรือไม่

คำตอบ:


792

คุณกำลังใช้|(ไพพ์) เพื่อกำหนดทิศทางเอาต์พุตของคำสั่งไปยังคำสั่งอื่น สิ่งที่คุณกำลังมองหาคือ&&โอเปอเรเตอร์เพื่อดำเนินการคำสั่งถัดไปหากคำสั่งก่อนหน้านี้ประสบความสำเร็จ:

cp /templates/apple /templates/used && cp /templates/apple /templates/inuse && rm /templates/apple

หรือ

cp /templates/apple /templates/used && mv /templates/apple /templates/inuse

ในการสรุปตัวดำเนินการ / ตัวคั่นคำสั่งของ bash (ไม่ใช่แบบละเอียด):

  • |ไพพ์ (ไพพ์ไลน์) เอาต์พุตมาตรฐาน ( stdout) ของหนึ่งคำสั่งลงในอินพุตมาตรฐานของอีกอันหนึ่ง โปรดทราบว่าstderrยังคงเข้าสู่ปลายทางเริ่มต้นไม่ว่าจะเกิดอะไรขึ้น
  • |&ไพพ์ทั้งสองstdoutและstderrหนึ่งคำสั่งลงในอินพุตมาตรฐานของอีกอันหนึ่ง มีประโยชน์มากใช้งานได้ใน bash เวอร์ชัน 4 ขึ้นไป
  • &&รันคำสั่งทางขวาของ&&เฉพาะถ้าคำสั่งก่อนหน้านี้ประสบความสำเร็จ
  • ||ดำเนินการคำสั่งทางขวาของ||เพียงคำสั่งก่อนหน้านี้ล้มเหลว
  • ;ดำเนินการคำสั่งทางขวามือของ;เสมอโดยไม่คำนึงว่าคำสั่งก่อนหน้านี้ประสบความสำเร็จหรือล้มเหลว ยกเว้นว่าset -eก่อนหน้านี้ถูกเรียกใช้ซึ่งทำให้bashล้มเหลวในข้อผิดพลาด

6
upvoted เอกสารอย่างเป็นทางการgnu.org/software/bash/manual/bash.html#Lists
flow2k

78

ทำไมไม่cpไปยังตำแหน่ง 1 จากนั้นmvไปยังตำแหน่งที่ 2 วิธีนี้จะช่วย "ลบ" ต้นฉบับ

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

cp file1 file2 ; cp file1 file3 ; rm file1

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

cp file1 file2 && cp file1 file3 && rm file1

ด้วยวิธีนี้หากcpคำสั่งใดคำสั่งหนึ่งล้มเหลวrmจะไม่ทำงาน


10

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


7

อีกตัวเลือกหนึ่งคือพิมพ์Ctrl+V Ctrl+Jที่ส่วนท้ายของแต่ละคำสั่ง

ตัวอย่าง (แทนที่#ด้วยCtrl+V Ctrl+J):

$ echo 1#
echo 2#
echo 3

เอาท์พุท:

1
2
3

สิ่งนี้จะดำเนินการคำสั่งโดยไม่คำนึงว่าคำสั่งก่อนหน้านี้ล้มเหลว

เหมือนกับ: echo 1; echo 2; echo 3

หากคุณต้องการหยุดการดำเนินการกับคำสั่งที่ล้มเหลวให้เพิ่ม&&ที่ส่วนท้ายของแต่ละบรรทัดยกเว้นคำสั่งสุดท้าย

ตัวอย่าง (แทนที่#ด้วยCtrl+V Ctrl+J):

$ echo 1 &&#
failed-command &&#
echo 2

เอาท์พุท:

1
failed-command: command not found

ในzshคุณยังสามารถใช้Alt+EnterหรือEsc+EnterแทนCtrl+V Ctrl+J



2

ใช้ท่อดูเหมือนว่าแปลกสำหรับฉัน อย่างไรก็ตามคุณควรใช้ตัวandดำเนินการ Bash แบบลอจิคัล:

$ cp /templates/apple /templates/used && cp /templates/apple /templates/inuse && rm /templates/apples

หากcpคำสั่งล้มเหลวrmจะไม่ถูกดำเนินการ

หรือคุณสามารถทำให้บรรทัดคำสั่งเนื้อหามากขึ้นโดยใช้ห่วงและforcmp

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