ตัวควบคุมและการเปลี่ยนเส้นทางของเชลล์คืออะไร


245

ฉันมักจะเห็นบทเรียนออนไลน์ที่เชื่อมต่อคำสั่งต่าง ๆ ด้วยสัญลักษณ์ที่แตกต่างกัน ตัวอย่างเช่น:

command1 |  command2
command1 &  command2
command1 || command2    
command1 && command2

คนอื่น ๆ ดูเหมือนจะเชื่อมต่อคำสั่งกับไฟล์:

command1  > file1
command1  >> file1

สิ่งเหล่านี้คืออะไร พวกเขาเรียกว่าอะไร พวกเขาทำอะไร? มีอะไรอีกบ้าง?


Meta หัวข้อเกี่ยวกับคำถามนี้ .

คำตอบ:


340

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

A. ผู้ประกอบการควบคุม

ในภาษาคำสั่งเชลล์โทเค็นที่ทำหน้าที่ควบคุม
มันเป็นหนึ่งในสัญลักษณ์ต่อไปนี้:

&   &&   (   )   ;   ;;   <newline>   |   ||

และ|&ในการทุบตี

!คือไม่ได้เป็นผู้ประกอบการควบคุม แต่ลิขสิทธิ์ของ Word มันจะกลายเป็นตรรกะไม่ใช่ [ตัวดำเนินการปฏิเสธ] ภายในนิพจน์เชิงคณิตศาสตร์และโครงสร้างการทดสอบภายใน (ในขณะที่ยังต้องการตัวคั่นช่องว่าง)

A.1 List terminators

  • ; : จะเรียกใช้คำสั่งหนึ่งคำสั่งหลังจากเสร็จสิ้นโดยไม่คำนึงถึงผลลัพธ์ของคำสั่งแรก

    command1 ; command2

    ครั้งแรกcommand1จะทำงานในเบื้องหน้าและเมื่อเสร็จแล้วcommand2จะถูกเรียกใช้

    ขึ้นบรรทัดใหม่ที่ไม่ได้อยู่ในสตริงตามตัวอักษรหรือหลังจากคำหลักบางคำไม่เท่ากับตัวดำเนินการเครื่องหมายอัฒภาค รายการ;คำสั่งแบบง่าย ๆ แบบมีตัวคั่นจะยังคงเป็นรายการ - ในตัวแยกวิเคราะห์ของเชลล์จะต้องอ่านต่อในคำสั่งแบบง่าย ๆ ที่ตาม;ด้วยคำสั่งแบบง่ายแบบมีตัวคั่นก่อนดำเนินการในขณะที่บรรทัดใหม่สามารถคั่นรายการคำสั่งทั้งหมด ความแตกต่างนั้นบอบบาง แต่ซับซ้อน: เนื่องจากเชลล์ไม่มีความจำเป็นก่อนหน้าสำหรับการอ่านข้อมูลตามบรรทัดใหม่บรรทัดใหม่ทำเครื่องหมายจุดที่เชลล์สามารถเริ่มประเมินคำสั่งง่าย ๆ ที่ได้อ่านมาแล้วในขณะที่;เซมิโคลอนทำ ไม่.

  • & : สิ่งนี้จะรันคำสั่งในพื้นหลังทำให้คุณสามารถทำงานต่อในเชลล์เดียวกันได้

     command1 & command2

    ที่นี่command1จะเปิดตัวในพื้นหลังและcommand2เริ่มทำงานในเบื้องหน้าทันทีโดยไม่ต้องรอcommand1ออก

    ขึ้นบรรทัดใหม่หลังจากcommand1เป็นตัวเลือก

A.2 ผู้ประกอบการตรรกะ

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

     command1 && command2

    ที่นี่command2จะทำงานหลังจากcommand1เสร็จสิ้นและต่อเมื่อcommand1สำเร็จ (หากรหัสออกเป็น 0) คำสั่งทั้งสองทำงานในเบื้องหน้า

    คำสั่งนี้ยังสามารถเขียนได้

    if command1
    then command2
    else false
    fi

    หรือif command1; then command2; fiหากสถานะการส่งคืนถูกละเว้น

  • || : ใช้เพื่อสร้างรายการหรือจะช่วยให้คุณสามารถเรียกใช้คำสั่งเดียวเท่านั้นหากอื่นออกจากไม่ประสบความสำเร็จ

     command1 || command2

    ที่นี่command2จะทำงานเฉพาะในกรณีที่command1ล้มเหลว (หากกลับสถานะการออกที่ไม่ใช่ 0) คำสั่งทั้งสองทำงานในเบื้องหน้า

    คำสั่งนี้ยังสามารถเขียนได้

    if command1
    then true
    else command2
    fi

    if ! command1; then command2; fiหรือในทางที่สั้นกว่า

    ทราบว่า&&และ||มีความสัมพันธ์ด้านซ้าย; ดูความสำคัญของตัวดำเนินการเชิงตรรกะของเชลล์ &&, || สำหรับข้อมูลเพิ่มเติม.

  • !: นี่เป็นคำที่สงวนไว้ซึ่งทำหน้าที่เป็นตัวดำเนินการ“ ไม่” (แต่ต้องมีตัวคั่น) ใช้ในการปฏิเสธสถานะการส่งคืนของคำสั่ง - ส่งคืน 0 หากคำสั่งส่งคืนสถานะที่ไม่ใช่ศูนย์ส่งคืน 1 หากส่งคืนสถานะ 0 ยังเป็นตรรกะไม่ได้สำหรับtestยูทิลิตี้

    ! command1
    
    [ ! a = a ]

    และตัวดำเนินการ NOT จริงภายในนิพจน์ทางคณิตศาสตร์:

    $ echo $((!0)) $((!23))
    1 0

A.3 ผู้ควบคุมท่อ

  • |: ตัวดำเนินการไพพ์มันส่งผ่านเอาต์พุตของคำสั่งหนึ่งเป็นอินพุตไปยังอีกคำสั่งหนึ่ง คำสั่งที่สร้างขึ้นจากผู้ประกอบท่อที่เรียกว่าท่อ

     command1 | command2

    ผลใด ๆ พิมพ์โดยcommand1จะถูกส่งเป็น input command2เพื่อ

  • |&: นี่คือการจดชวเลข2>&1 |ในทุบตีและ zsh มันส่งผ่านทั้งเอาต์พุตมาตรฐานและข้อผิดพลาดมาตรฐานของคำสั่งหนึ่งเป็นอินพุตไปยังอีก

    command1 |& command2

A.4 เครื่องหมายวรรคตอนรายการอื่น ๆ

;;ใช้เพื่อทำเครื่องหมายจุดสิ้นสุดของคำสั่ง Caseเท่านั้น Ksh, bash และ zsh ยังรองรับ;&การผ่านไปยังเคสถัดไปและ;;&(ไม่ใช่ ATT ksh) เพื่อดำเนินการต่อและทดสอบเคสถัดไป

(และ)ถูกใช้เพื่อจัดกลุ่มคำสั่งและเรียกใช้งานใน subshell {และ}กลุ่มคำสั่ง แต่ไม่เปิดพวกเขาใน subshell ดูคำตอบนี้สำหรับการอภิปรายเกี่ยวกับวงเล็บประเภทต่างๆวงเล็บและวงเล็บปีกกาในไวยากรณ์เชลล์

B. ผู้ประกอบการเปลี่ยนเส้นทาง

ผู้ประกอบการเปลี่ยนเส้นทาง

ในภาษาคำสั่งเชลล์โทเค็นที่ทำหน้าที่เปลี่ยนเส้นทาง มันเป็นหนึ่งในสัญลักษณ์ต่อไปนี้:

<     >     >|     <<     >>     <&     >&     <<-     <>

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

  • < : ให้อินพุตกับคำสั่ง

    command < file.txt

    ดังกล่าวข้างต้นจะดำเนินการในเนื้อหาของcommandfile.txt

  • <>: เหมือนข้างบน แต่ไฟล์เปิดในโหมดอ่าน + เขียนแทนการอ่านอย่างเดียว :

    command <> file.txt

    หากไฟล์ไม่มีอยู่ไฟล์นั้นจะถูกสร้างขึ้น

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

  • > : กำหนดทิศทางเอาต์พุตของคำสั่งให้เป็นไฟล์

    command > out.txt

    ดังกล่าวข้างต้นจะช่วยให้การส่งออกของเป็นcommand out.txtหากไฟล์มีอยู่เนื้อหาจะถูกเขียนทับและหากไม่มีไฟล์นั้นจะถูกสร้างขึ้น

    โอเปอเรเตอร์นี้มักถูกใช้เพื่อเลือกว่าควรพิมพ์สิ่งใดไปยังข้อผิดพลาดมาตรฐานหรือเอาต์พุตมาตรฐาน :

    command >out.txt 2>error.txt

    ในตัวอย่างข้างต้น>จะเปลี่ยนเส้นทางเอาต์พุตมาตรฐานและ2>เปลี่ยนเส้นทางข้อผิดพลาดมาตรฐาน การส่งออกนอกจากนี้ยังสามารถเปลี่ยนเส้นทางไปใช้1>แต่ตั้งแต่นี้เป็นค่าเริ่มต้นที่มักจะมองข้ามและก็เขียนเป็นเพียง1>

    ดังนั้นเพื่อให้ทำงานcommandบนfile.txtและบันทึกการส่งออกในout.txtและข้อความผิดพลาดใด ๆ ในการerror.txtที่คุณจะเรียกใช้:

    command < file.txt > out.txt 2> error.txt
  • >|: ทำเช่นเดียวกัน>แต่จะเขียนทับเป้าหมายแม้ว่าเชลล์ได้รับการกำหนดค่าให้ปฏิเสธการเขียนทับ (ด้วยset -Cหรือset -o noclobber)

    command >| out.txt

    หากout.txtมีอยู่เอาต์พุตของcommandจะแทนที่เนื้อหา หากไม่มีอยู่มันจะถูกสร้างขึ้น

  • >>: ทำเช่นเดียวกัน>ยกเว้นว่ามีไฟล์เป้าหมายอยู่ข้อมูลใหม่จะถูกต่อท้าย

    command >> out.txt

    หากout.txtมีอยู่เอาต์พุตของcommandจะถูกต่อท้ายหลังจากสิ่งที่มีอยู่แล้ว หากไม่มีอยู่มันจะถูกสร้างขึ้น

  • &>, >&, >>&และ&>>(ที่ไม่ได้มาตรฐาน) เปลี่ยนเส้นทางทั้งข้อผิดพลาดมาตรฐานและเอาต์พุตมาตรฐานการแทนที่หรือต่อท้ายตามลำดับ

    command &> out.txt

    ทั้งข้อผิดพลาดมาตรฐานและผลลัพธ์มาตรฐานของcommandจะถูกบันทึกไว้out.txtเขียนทับเนื้อหาหรือสร้างมันหากไม่มีอยู่

    command &>> out.txt

    ข้างต้นยกเว้นว่าถ้าout.txtมีอยู่เอาต์พุตและข้อผิดพลาดของcommandจะถูกผนวกเข้ากับมัน

    &>ตัวแปรต้นกำเนิดในbashขณะที่>&ตัวแปรมาจาก csh (ทศวรรษที่ผ่านมาก่อนหน้านี้) ทั้งคู่ขัดแย้งกับตัวดำเนินการเชลล์ POSIX อื่น ๆ และไม่ควรใช้ในshสคริปต์แบบพกพา

  • <<: เอกสารที่นี่ มันมักจะใช้ในการพิมพ์สตริงหลายบรรทัด

     command << WORD
         Text
     WORD

    ที่นี่commandจะใช้ทุกอย่างจนกว่าจะพบการเกิดขึ้นต่อไปของWORD, Textในตัวอย่างข้างต้นเป็น input ในขณะที่WORDมักจะEoFหรือรูปแบบนั้นมันอาจเป็นสตริงตัวอักษรและตัวเลข (และไม่เพียง) สตริงที่คุณต้องการ เมื่อWORDยกมาข้อความในเอกสารที่นี่จะได้รับการปฏิบัติอย่างแท้จริงและไม่มีการขยายตัว (เช่นตัวแปร) หากไม่มีการอ้างอิงตัวแปรจะถูกขยาย สำหรับรายละเอียดเพิ่มเติมโปรดดูที่คู่มือการทุบตี

    หากคุณต้องการไพพ์เอาต์พุตcommand << WORD ... WORDโดยตรงไปยังคำสั่งหรือคำสั่งอื่นคุณต้องวางไพพ์ไว้ในบรรทัดเดียวกับ<< WORDคุณไม่สามารถวางมันได้หลังจากการยกเลิก WORD หรือบนบรรทัดต่อไปนี้ ตัวอย่างเช่น:

     command << WORD | command2 | command3...
         Text
     WORD
  • <<<: นี่คือสตริงคล้ายกับเอกสารที่นี่ แต่มีไว้สำหรับบรรทัดเดียว สิ่งเหล่านี้มีอยู่เฉพาะในพอร์ต Unix หรือ rc (ซึ่งต้นกำเนิด), zsh, การใช้งานบางอย่างของ ksh, yash และ bash

    command <<< WORD

    สิ่งที่จะได้รับเป็นWORDขยายตัวและความคุ้มค่าของมันจะถูกส่งเป็น input commandเพื่อ สิ่งนี้มักถูกใช้เพื่อส่งผ่านเนื้อหาของตัวแปรเป็นอินพุตไปยังคำสั่ง ตัวอย่างเช่น:

     $ foo="bar"
     $ sed 's/a/A/' <<< "$foo"
     bAr
     # as a short-cut for the standard:
     $ printf '%s\n' "$foo" | sed 's/a/A/'
     bAr
     # or
     sed 's/a/A/' << EOF
     $foo
     EOF

สามารถใช้ตัวดำเนินการอื่น ( >&-, x>&y x<&y) เพื่อปิดหรือทำซ้ำตัวให้คำอธิบายไฟล์ได้ สำหรับรายละเอียดเกี่ยวกับพวกเขาโปรดดูส่วนที่เกี่ยวข้องของคู่มือเปลือกของคุณ ( ที่นี่เช่นสำหรับทุบตี)

สิ่งนี้ครอบคลุมเฉพาะโอเปอเรเตอร์ที่ใช้กันมากที่สุดของเชลล์แบบบอร์น เชลล์บางตัวมีโอเปอเรเตอร์การเปลี่ยนเส้นทางเพิ่มเติมเล็กน้อย

ksh, ทุบตีและ zsh ยังมีโครงสร้าง<(…), >(…)และ=(…)(ที่หนึ่งหลังในzshเท่านั้น) เหล่านี้จะไม่เปลี่ยนเส้นทาง แต่กระบวนการทดแทน


2
มันอาจจะคุ้มค่าที่จะสังเกตว่าเชลล์บางตัวนั้นไม่เท่ากันและเน้นเฉพาะคุณลักษณะเฉพาะของ bash
Greg Hewgill

1
@GregHewgill ใช่ฉัน weaseled bashออกมาจากมันด้วยการบอกว่าฉันกำลังพูดคุยเกี่ยวกับการ คำถามนี้ได้รับการดูแลเป็นอย่างดีเพื่อปิดคำถาม "สิ่งนี้แปลกประหลาดทำอะไร" และส่วนใหญ่มาจากผู้ใช้ทุบตี ฉันหวังว่าจะมีคนอื่นขว้างและตอบโต้สำหรับกระสุนที่ไม่ใช่กระสุนทุบตี แต่การเน้นที่วัตถุทุบตีที่เฉพาะเจาะจงนั้นสมเหตุสมผลมาก ฉันจะต้องตรวจสอบว่าฉันไม่ทราบว่าพวกเขาอยู่ด้านบนของหัวของฉัน
terdon

&>, >>>และ<<<ทั้งหมดไม่ใช่ตำแหน่งที่อ้างอิงถึงตัวอักษรที่ไม่ใช่ตัวอักษรอัลฟานัมไม่ใช่เฉพาะในชื่อ here-doc คำตอบนี้ยังกล่าวถึงน้อยมากเกี่ยวกับวิธีการทำงาน - ตัวอย่างเช่นมันเกือบจะแย่กว่าไร้ประโยชน์ที่จะพูดถึงคำสั่งง่ายๆและคำสั่งโดยไม่อธิบายว่าสิ่งเหล่านี้คืออะไรและการตัดสินใจของเชลล์อย่างไร
mikeserv

@mikeserv ขอบคุณ พวกเขาทำงานกับทุบตีและ zsh แม้ว่า ฉันไม่ทราบว่ามีอะไรเฉพาะเจาะจงในการทุบตีอย่างแท้จริงในรายการนั้น ฉันควรทำสิ่งนี้และเพิ่มเปลือกหอยแต่ละงาน แต่จะเกี่ยวข้องกับการค้นหาก่อน
terdon

1
@ Arc676 ไม่พวกเขาไม่ได้ประเมินว่าเป็นจริงหรือเท็จนั่นคือบริบทที่แตกต่างอย่างสิ้นเชิง นี่หมายความว่าค่าการออกที่ไม่ใช่ 0 หมายถึงปัญหา (ไม่ใช่false) และรหัสทางออก 0 หมายถึงความสำเร็จ (ไม่ใช่true) นั่นเป็นวิธีที่ได้มาตรฐานเสมอ รหัสออกที่ไม่ใช่ 0 บ่งชี้ถึงข้อผิดพลาดในทุกสภาพแวดล้อมที่ฉันรู้จัก
terdon

60

คำเตือนเกี่ยวกับ '>'

ผู้เริ่มต้น Unix ที่เพิ่งเรียนรู้เกี่ยวกับการเปลี่ยนเส้นทาง I / O ( <และ>) มักจะลองทำสิ่งต่าง ๆ เช่น

คำสั่งinput_file > the_same_file

หรือ

คำสั่ง … < ไฟล์      > the_same_file

หรือเกือบเท่ากัน

แมวไฟล์ | คำสั่ง …> the_same_file

( grep, sed, cut, sortและspellเป็นตัวอย่างของคำสั่งที่ผู้คนกำลังล่อลวงเพื่อใช้ในการสร้างเช่นนี้.) ผู้ใช้จะประหลาดใจที่พบว่าสถานการณ์เหล่านี้ส่งผลให้ในไฟล์กลายเป็นที่ว่างเปล่า

ความแตกต่างที่ดูเหมือนจะไม่ได้กล่าวถึงในคำตอบอื่น ๆ สามารถพบได้ในประโยคแรกของส่วนการเปลี่ยนเส้นทางของbash (1) :

ก่อนที่จะดำเนินการคำสั่งอินพุตและเอาต์พุตอาจถูกเปลี่ยนทิศทาง โดยใช้สัญลักษณ์พิเศษที่ตีความโดยเชลล์

ห้าคำแรกควรจะเป็นตัวหนาตัวเอียงขีดเส้นใต้ขยายกระพริบสีแดงและมีเครื่องหมายเครื่องหมายตกใจในรูปสามเหลี่ยมสีแดงไอคอนเพื่อเน้นความจริงที่ว่าเปลือกดำเนินการเปลี่ยนเส้นทางการร้องขอ (s) ก่อนที่คำสั่งจะถูกดำเนินการ และจำไว้ด้วย

การเปลี่ยนเส้นทางของผลลัพธ์ทำให้ไฟล์…ถูกเปิดเพื่อเขียน…. หากไฟล์ไม่มีอยู่ไฟล์จะถูกสร้างขึ้น ถ้ามันมีอยู่มันจะถูกตัดให้มีขนาดเป็นศูนย์

  1. ดังนั้นในตัวอย่างนี้:

    sort roster > roster

    เชลล์จะเปิดrosterไฟล์เพื่อเขียนตัดทอน (เช่นการละทิ้งเนื้อหาทั้งหมด) ก่อนที่sortโปรแกรมจะเริ่มทำงาน โดยธรรมชาติแล้วไม่มีสิ่งใดที่สามารถกู้คืนข้อมูลได้

  2. บางคนอาจคาดหวังอย่างนั้นไม่ได้

    tr "[:upper:]" "[:lower:]" < poem > poem

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

ดังนั้นจะทำอย่างไรกับมัน?

โซลูชั่นรวมถึง:

  • ตรวจสอบว่าโปรแกรมที่คุณกำลังเรียกใช้มีความสามารถของตัวเองภายในความสามารถในการระบุตำแหน่งที่จะออก ซึ่งมักจะถูกระบุด้วยโทเค็น-o(หรือ--output=) โดยเฉพาะอย่างยิ่ง,

    sort roster -o roster

    เทียบเท่ากับ

    sort roster > roster

    ยกเว้นในกรณีแรกsortโปรแกรมจะเปิดไฟล์เอาต์พุต และมันก็ฉลาดพอที่จะไม่เปิดไฟล์ที่ส่งออกจนกระทั่งหลังจากที่มันได้อ่านทั้งหมดของแฟ้มใส่ (s)

    ในทำนองเดียวกันอย่างน้อยบางรุ่นsedมี-i(แก้ไขฉัน n วาง) ตัวเลือกที่สามารถนำมาใช้ในการเขียนการส่งออกกลับออกไปยังแฟ้มใส่ (อีกครั้งหลังจากที่ป้อนข้อมูลทั้งหมดที่ได้รับการอ่าน) บรรณาธิการเช่นed/ ex, emacs, picoและvi/ vim อนุญาตให้ผู้ใช้แก้ไขไฟล์ข้อความและบันทึกข้อความที่แก้ไขในไฟล์ต้นฉบับ โปรดทราบว่าed(อย่างน้อย) สามารถใช้แบบไม่โต้ตอบ

    • viมีคุณสมบัติที่เกี่ยวข้อง หากคุณพิมพ์มันจะเขียนเนื้อหาของบัฟเฟอร์การแก้ไขออกไปอ่านเอาต์พุตและแทรกลงในบัฟเฟอร์ (แทนที่เนื้อหาต้นฉบับ):%!commandEntercommand
  • เรียบง่าย แต่มีประสิทธิภาพ:

    คำสั่งinput_file > temp_file   && mv temp_file  input_file

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

    รูปแบบ:

    • commandinput_file > temp_file && cp temp_file input_file && rm temp_file
      ซึ่งจะยังคง (อาจ) ปล่อยให้temp_fileโลกสามารถอ่านได้ ดียิ่งขึ้น:
    • cp input_file temp_file && commandtemp_file > input_file && rm temp_file
      สิ่งเหล่านี้จะรักษาสถานะลิงก์เจ้าของและโหมด (การป้องกัน) ของไฟล์ซึ่งอาจมีค่าใช้จ่าย I / O มากเป็นสองเท่า (คุณอาจต้องใช้ตัวเลือกเช่น-aหรือ-pเปิดcp เพื่อบอกให้รักษาแอตทริบิวต์)
    • commandinput_file > temp_file &&
      cp --attributes-only --preserve=all input_file temp_file &&
      mv temp_file input_file
      (แยกออกเป็นบรรทัดแยกกันเพื่อให้สามารถอ่านได้เท่านั้น) วิธีนี้จะรักษาโหมดของไฟล์ไว้ (และหากคุณเป็นเจ้าของ, เจ้าของ) แต่ทำให้มันเป็นของคุณ (ถ้าคุณไม่ได้รูท) และทำให้มันใหม่ แยกไฟล์
  • บล็อกนี้ (แก้ไข "ไฟล์") แนะนำและอธิบาย

    {rm input_file   &&   คำสั่ง …> input_file ; } < input_file

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

  • แพ็คเกจ moreutils มีคำสั่งที่เรียกว่าsponge:

    คำสั่งinput_file | ฟองน้ำthe_same_file

    ดูคำตอบนี้สำหรับข้อมูลเพิ่มเติม

นี่คือสิ่งที่ทำให้ฉันประหลาดใจโดยสมบูรณ์: syntaxerror พูดว่า :

[โซลูชันเหล่านี้ส่วนใหญ่] จะล้มเหลวในระบบไฟล์แบบอ่านอย่างเดียวโดยที่“ อ่านอย่างเดียว” หมายความว่าคุณ$HOME จะเขียนได้ แต่/tmpจะอ่านได้อย่างเดียว (โดยค่าเริ่มต้น) ตัวอย่างเช่นหากคุณมี Ubuntu และคุณได้บูทเข้าสู่ Recovery Console นี่เป็นกรณีปกติ นอกจากนี้ผู้ประกอบการเอกสารที่นี่<<<จะไม่ทำงานที่นั่นเพราะมันจะต้อง/tmpมีการอ่าน / เขียน เพราะมันจะเขียนไฟล์ชั่วคราวลงไปที่นั่นเช่นกัน
(เทียบกับคำถามนี้รวมstraceเอาท์พุท 'd)

กรณีต่อไปนี้อาจใช้งานได้:

  • สำหรับผู้ใช้ขั้นสูงเท่านั้น: หากคำสั่งของคุณมีการประกันเพื่อการผลิตจำนวนเดียวกันของข้อมูลการส่งออกที่มีการป้อนข้อมูล (เช่นsortหรือtr โดยไม่ต้อง-dหรือ-sตัวเลือก), คุณสามารถลอง
    คำสั่งinput_file | dd of = the_same_file conv = notrunc
    ดูคำตอบนี้ และคำตอบนี้สำหรับข้อมูลเพิ่มเติมรวมถึงคำอธิบายข้างต้นและทางเลือกที่ใช้งานได้หากคำสั่งของคุณรับประกันว่าจะสร้างข้อมูลเอาต์พุตจำนวนเท่ากันตามที่มีอินพุตหรือน้อยกว่า (เช่นgrepหรือcut) คำตอบเหล่านี้มีข้อได้เปรียบที่พวกเขาไม่ต้องการพื้นที่ว่างใด ๆ (หรือพวกเขาต้องการน้อยมาก) คำตอบข้างต้นของแบบฟอร์ม อย่างชัดเจนต้องการให้มีพื้นที่ว่างเพียงพอสำหรับระบบเพื่อให้สามารถเก็บไฟล์อินพุต (เก่า) ทั้งหมดและไฟล์เอาต์พุต (ใหม่) พร้อมกัน นี่ไม่ใช่ความจริงที่เห็นได้ชัดสำหรับโซลูชันอื่น ๆ ส่วนใหญ่ (เช่นและ) เช่นกัน ข้อยกเว้น: อาจจะต้องใช้พื้นที่ว่างจำนวนมากเพราะcommandinput_file > temp_file && …sed -ispongesort … | dd …sort จำเป็นต้องอ่านอินพุตทั้งหมดก่อนจึงจะสามารถเขียนเอาต์พุตใด ๆ ได้และอาจเป็นบัฟเฟอร์มากที่สุดหากไม่ใช่ข้อมูลทั้งหมดในไฟล์ชั่วคราว
  • สำหรับผู้ใช้ขั้นสูงเท่านั้น:
    คำสั่งinput_file 1 <> the_same_file
    อาจเทียบเท่ากับddคำตอบข้างต้น ไวยากรณ์เปิดไฟล์ชื่อที่บ่งไฟล์สำหรับทั้งเข้าและส่งออกโดยไม่มีการตัดทอนมัน - การเรียงลำดับของการรวมกันของและ หมายเหตุ: บางโปรแกรม (เช่นและ) อาจปฏิเสธที่จะทำงานในสถานการณ์นี้เนื่องจากสามารถตรวจพบว่าอินพุตและเอาต์พุตเป็นไฟล์เดียวกัน ดูคำตอบนี้ สำหรับการอภิปรายของดังกล่าวข้างต้นและสคริปต์ที่ทำให้การทำงานคำตอบนี้ถ้าคำสั่งของคุณมีการประกันเพื่อการผลิตจำนวนเดียวกันของข้อมูลการส่งออกที่มีการป้อนข้อมูลหรือน้อยกว่า คำเตือน: ฉันยังไม่ได้ทดสอบสคริปต์ของปีเตอร์ดังนั้นฉันจึงไม่รับรองn<> filen n<n>catgrep

แล้วคำถามคืออะไร

นี่เป็นหัวข้อยอดนิยมใน U&L; มันถูกแก้ไขในคำถามต่อไปนี้:

…และนั่นไม่ใช่การนับผู้ใช้ขั้นสูงหรือถามอูบุนตู ฉันได้รวมข้อมูลจำนวนมากจากคำตอบของคำถามข้างต้นไว้ในคำตอบนี้ แต่ไม่ใช่ทั้งหมด (เช่นสำหรับข้อมูลเพิ่มเติมอ่านคำถามข้างต้นและคำตอบของพวกเขา)

ป.ล. ฉันไม่มีส่วนเกี่ยวข้องกับบล็อกที่ฉันอ้างถึงด้านบน


เนื่องจากคำถามนี้ยังคงเกิดขึ้นฉันคิดว่าฉันลองเขียน“ คำตอบที่ยอมรับได้” ฉันควรโพสต์ไว้ที่นี่ (และอาจเชื่อมโยงไปยังคำถามอื่น ๆ ที่ถูกค้ามนุษย์อย่างหนัก) หรือฉันควรย้ายไปยังหนึ่งในคำถามที่ก่อให้เกิดปัญหานี้จริงหรือ นอกจากนี้อาจเป็นสถานการณ์ที่ควรรวมคำถามหรือไม่
สกอตต์

/ tmp ไดเร็กทอรีพร้อมใช้งานสำหรับแอ็พพลิเคชันที่ต้องการตำแหน่งเพื่อสร้างไฟล์ชั่วคราว แอปพลิเคชันจะได้รับอนุญาตให้สร้างไฟล์ในไดเรกทอรีนี้ แต่จะไม่ถือว่าไฟล์ดังกล่าวถูกสงวนไว้ระหว่างการเรียกใช้แอปพลิเคชัน
mikeserv

@mikeserv: ใช่ (1) ฉันอ้างถึงไวยากรณ์และ (2) ฉันบอกว่าฉันประหลาดใจ /tmpผมคิดว่าถ้ามีอะไรจะอ่านเขียนก็จะ
สกอตต์

สิ่งที่ @syntaxerror พูดนั้นแปลก ๆ เป็นสองเท่าเพราะอย่างที่ฉันคิดว่าdashจะเป็นเชลล์กู้คืนเริ่มต้นบน Ubuntu และมันไม่เพียง แต่ไม่เข้าใจ<<<herestring แต่มันยังได้รับท่อนิรนามสำหรับ<<heredocuments และไม่ยุ่งกับ${TMPDIR:-/tmp}สิ่งนั้น วัตถุประสงค์ทั้งหมด ดูสิ่งนี้หรือสิ่งนี้สำหรับการสาธิตเกี่ยวกับการจัดการเอกสารที่นี่ ทำไมปริมาณเท่ากันหรือน้อยกว่าคำเตือน?
mikeserv

@mikeserv: ดีdd … conv=notruncและ1<>คำตอบไม่เคยตัดทอนไฟล์เอาต์พุตดังนั้นหากเอาต์พุตของคำสั่งน้อยกว่าอินพุต (เช่นgrep) จะมีบางไบต์ของต้นฉบับที่เหลืออยู่ที่ท้ายไฟล์ และถ้าหากการส่งออกมีขนาดใหญ่กว่าการป้อนข้อมูล (เช่นcat -n, nlหรือ (อาจ) grep -n) มีความเสี่ยงของการเขียนทับข้อมูลเก่าก่อนที่คุณจะได้อ่านมัน
สกอตต์

29

ข้อสังเกตเพิ่มเติมเกี่ยวกับ;, &, (และ)

  • โปรดทราบว่าบางคำสั่งในคำตอบของ terdon อาจเป็นโมฆะ ตัวอย่างเช่นคุณสามารถพูดได้

    command1 ;

    (ไม่มีcommand2) สิ่งนี้เทียบเท่า

    command1

    (กล่าวคือมันทำงานcommand1ในเบื้องหน้าและรอให้เสร็จสมบูรณ์

    command1 &

    (ไม่รวมcommand2) จะเปิดใช้งานcommand1ในพื้นหลังแล้วออก shell prompt อื่นทันที

  • ในทางตรงกันข้ามcommand1 &&, command1 ||และcommand1 |ไม่ทำให้รู้สึกใด ๆ หากคุณพิมพ์หนึ่งในเหล่านี้เชลล์จะ (อาจ) สันนิษฐานว่าคำสั่งดำเนินการต่อไปยังบรรทัดอื่น มันจะแสดงพรอมต์เชลล์ (ความต่อเนื่อง) ที่สองซึ่งตามปกติแล้วจะตั้งไว้ที่>และอ่านต่อไป ในเชลล์สคริปต์มันจะอ่านบรรทัดถัดไปและต่อท้ายสิ่งที่มันได้อ่านแล้ว (ระวัง: นี่อาจไม่ใช่สิ่งที่คุณต้องการจะเกิดขึ้น)

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

    command1  &&  \
    command2

    หรือ

    find starting-directory -mindepth 3 -maxdepth 5 -iname "*.some_extension" -type f \
                            -newer some_existing_file -user fred -readable -print
  • ในฐานะที่เป็น terdon พูด(และ)สามารถใช้ในการจัดกลุ่มคำสั่ง ข้อความที่ว่า“ ไม่เกี่ยวข้องจริงๆ” กับการอภิปรายนั้นเป็นที่ถกเถียงกัน บางส่วนของคำสั่งในคำตอบ terdon อาจจะเป็นคำสั่งกลุ่ม ตัวอย่างเช่น,

    ( command1 ; command2 )  &&  ( command3; command4 )

    ทำสิ่งนี้:

    • เรียกใช้command1และรอให้เสร็จ
    • จากนั้นโดยไม่คำนึงถึงผลลัพธ์ของการรันคำสั่งแรกนั้นให้รันcommand2และรอให้คำสั่งนั้นเสร็จสิ้น
    • ถ้าcommand2สำเร็จ

      • เรียกใช้command3และรอให้เสร็จ
      • จากนั้นโดยไม่คำนึงถึงผลลัพธ์ของการรันคำสั่งนั้นให้รันcommand4และรอให้คำสั่งนั้นเสร็จสิ้น

      หากcommand2ล้มเหลวหยุดการประมวลผลบรรทัดคำสั่ง

  • วงเล็บข้างนอก|นั้นแน่นมากดังนั้น

    command1 | command2 || command3

    เทียบเท่ากับ

    ( command1 | command2 )  ||  command3

    และ&&และ||ผูกแน่นกว่า;ดังนั้น

    command1 && command2 ; command3

    เทียบเท่ากับ

    ( command1 && command2 ) ;  command3

    กล่าวคือcommand3จะดำเนินการโดยไม่คำนึงถึงสถานะออกจากและcommand1 / หรือcommand2


สมบูรณ์แบบ +1! ฉันบอกว่าพวกเขาไม่เกี่ยวข้องเพราะฉันไม่ต้องการที่จะลงรายละเอียดมาก ฉันต้องการคำตอบที่สามารถใช้เป็นสูตรโกงอย่างรวดเร็วสำหรับมือใหม่ที่สงสัยว่า squiggles แปลก ๆ ในตอนท้ายของคำสั่งต่าง ๆ คืออะไร ฉันไม่ได้หมายความว่าพวกเขาไม่มีประโยชน์ ขอบคุณที่เพิ่มสิ่งนี้ทั้งหมด
terdon

1
ฉันกังวลเกี่ยวกับปัญหา "มวลวิกฤต" - ถ้าเราโพสต์ทุกสิ่งที่เราอาจจะพูดเกี่ยวกับหอยเราจะจบลงด้วยTLของเราเองคู่มืออ้างอิง Bash รุ่นDR
G-Man

ด้วยมูลค่าการกล่าวถึง: แตกต่างในภาษาของตระกูล C, ;ด้วยตัวเอง (หรือไม่มีคำสั่งก่อนหน้านี้) เป็นข้อผิดพลาดทางไวยากรณ์และไม่ใช่คำสั่งที่ว่างเปล่า ดังนั้นจึง; ;เป็นข้อผิดพลาด (ข้อผิดพลาดทั่วไปสำหรับผู้ใช้ใหม่คือ IMHO) นอกจากนี้: ;;เป็นตัวคั่นพิเศษสำหรับcaseข้อความสั่ง
muru

1
@muru: จุดดี แต่ขอพูดคุยกัน ใด ๆของผู้ประกอบการควบคุมที่สามารถปรากฏระหว่างคำสั่ง: ;, &&, ||, &และ|มีข้อผิดพลาดถ้าพวกเขาปรากฏขึ้นพร้อมกับอะไรก่อนหน้านี้พวกเขา นอกจากนี้ terdon ยังตอบ;;(สั้น ๆ ) ในคำตอบของเขา
G-Man

1
@ Wildcard: ตกลงฉันเห็นว่าคุณมาจากไหน คำสำคัญคือ "อาจ"; ทั้งหมดที่ฉันพูดก็คือฉันไม่รับประกันว่ากระสุนทั้งหมดจะยอมรับโครงสร้างดังกล่าว (เช่น YMMV) เห็นได้ชัดว่าฉันเขียนว่าก่อนที่ฉันจะรู้เกี่ยวกับการใช้linebreakโทเค็นในไวยากรณ์เชลล์ POSIX ดังนั้นอาจจะปลอดภัยถ้าจะบอกว่าเชลล์ที่สอดคล้องกับ POSIX ทั้งหมดจะยอมรับมัน ฉันยืนตามคำชี้แจงของฉันเป็นข้อจำกัดความรับผิดชอบทั่วไป หากคุณพบ pre-POSIX shell ที่เพียงพอเช่น shell Bourne ที่แท้จริงหรือเก่ากว่าการเดิมพันทั้งหมดจะปิด
G-Man
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.