ทำไมบางคำสั่งไม่อ่านจากอินพุตมาตรฐาน?


19

ฉันสงสัยว่าเมื่อไหร่ที่เราควรใช้ไปป์ไลน์และเมื่อใดที่เราไม่ควรทำ

พูดเช่นเพื่อฆ่ากระบวนการบางอย่างที่จัดการไฟล์ pdf ข้อมูลต่อไปนี้จะไม่ทำงานโดยใช้ไปป์ไลน์:

ps aux | grep pdf | awk '{print $2}'|kill

แต่เราสามารถทำได้ด้วยวิธีต่อไปนี้เท่านั้น:

kill $(ps aux| grep pdf| awk '{print $2}')

หรือ

ps aux | grep pdf | awk '{print $2}'| xargs kill

อ้างอิงจากman bash(เวอร์ชั่น4.1.2):

The standard output of command is connected via a pipe to the standard input of command2.

สำหรับสถานการณ์ข้างต้น:

  • stdin ของgrepเป็น stdout psของ ที่ได้ผล
  • stdin ของawkเป็น stdout grepของ ที่ได้ผล
  • stdin ของkillเป็น stdout awkของ ไม่ได้ผล

stdin ของคำสั่งต่อไปนี้จะรับอินพุตจาก stdout ของคำสั่งก่อนหน้าเสมอ

  • ทำไมไม่ได้ทำงานร่วมกับkillหรือrm?
  • สิ่งที่แตกต่างระหว่างkill, rmการป้อนข้อมูลด้วยgrep, awkการป้อนข้อมูล?
  • มีกฎอะไรบ้าง?

1
นี้ไม่ได้เป็นคำตอบ แต่คุณอาจต้องการที่จะมีลักษณะที่เป็นpgrep, pkillและkillallคำสั่ง
terdon

2
@terdon: ฉันเพียงแค่ใช้ด้านบนสถานการณ์ที่จะแสดงปัญหาท่อฉันเข้าใจว่าpgrepและส่วนที่เหลือสามารถบรรลุนี้ได้อย่างสมบูรณ์แบบ :)
sylye

คำตอบ:


17

มีวิธีการทั่วไปสองวิธีในการมอบอินพุตให้กับโปรแกรม:

  • ให้ข้อมูลกับ STDIN ของกระบวนการ
  • ระบุอาร์กิวเมนต์บรรทัดคำสั่ง

killใช้อาร์กิวเมนต์บรรทัดคำสั่งเท่านั้น ไม่ได้อ่านจาก STDIN โปรแกรมที่ชอบgrepและawkอ่านจาก STDIN (หากไม่มีการกำหนดชื่อไฟล์เป็นอาร์กิวเมนต์บรรทัดคำสั่ง) และประมวลผลข้อมูลตามอาร์กิวเมนต์บรรทัดคำสั่ง (รูปแบบ, คำสั่ง, แฟล็ก, ... )

คุณสามารถไพพ์ไปที่ STDIN ของกระบวนการอื่นเท่านั้นไม่ใช่ไปที่อาร์กิวเมนต์บรรทัดคำสั่ง

กฎทั่วไปคือว่าโปรแกรมใช้ STDIN เพื่อประมวลผลข้อมูลตามอำเภอใจ พารามิเตอร์อินพุตพิเศษทั้งหมดหรือหากมีเพียงไม่กี่ตัวเท่านั้นจะถูกส่งผ่านโดยอาร์กิวเมนต์บรรทัดคำสั่ง หากบรรทัดคำสั่งยาวเกินไปตัวอย่างเช่นawkข้อความของโปรแกรมที่ยาวมักมีความเป็นไปได้ที่จะอ่านไฟล์เหล่านี้จากไฟล์โปรแกรมพิเศษ ( -fตัวเลือกawk)

หากต้องการใช้ STDOUT ของโปรแกรมที่เป็นข้อโต้แย้งบรรทัดคำสั่งการใช้งานหรือในกรณีของข้อมูลจำนวนมาก$(...) ยังสามารถนี้โดยตรงกับxargsfind-exec ... {} +

เพื่อความสมบูรณ์: การเขียนอาร์กิวเมนต์บรรทัดคำสั่งเพื่อ STDOUT echoใช้


1
เราจะรู้ได้อย่างไรว่าคำสั่งจะรับอาร์กิวเมนต์แต่ไม่ใช่ STDIN? มีวิธีที่เป็นระบบหรือเป็นโปรแกรมแทนที่จะคาดเดาหรืออ่านจากหน้าคน? โดยการอ่านหน้า man เท่านั้นฉันไม่สามารถรับเบาะแสเฉพาะใด ๆ ที่จะยืนยันได้ว่าคำสั่งสามารถหรือไม่สามารถใช้ STDIN ได้เนื่องจาก STDIN นั้นเป็นส่วนหนึ่งของข้อโต้แย้งจากวิธีที่หน้า man อยู่ด้วย ตัวอย่างเช่นgzipใน SYNOPSIS มันไม่ได้บอกว่าต้องใช้ชื่อไฟล์เป็นอินพุต ฉันกำลังมองหาวิธีที่เป็นระบบมากขึ้นในการพิจารณาว่า
sylye

นอกจากนี้ยังมีอาร์กิวเมนต์ "-" ซึ่งหมายถึง "stdin" (หรือ "stdout") สำหรับคำสั่งบางอย่าง
Emmanuel

ไม่xargsอนุญาตให้คุณ "ไปป์อาร์กิวเมนต์บรรทัดคำสั่ง" อย่างแม่นยำหรือไม่
ต. Verron

@ T.Verron xargsใช่นี้เป็นงานของ มันเรียกคำสั่งถ้าจำเป็นมากกว่าหนึ่งครั้ง (ขนาดบรรทัดคำสั่งถูก จำกัด ) และมีตัวเลือกอื่น ๆ อีกมากมาย
jofel

2
ข้อความของคำอธิบายจะอธิบายวิธีการใช้งานโปรแกรม ตัวอย่างเช่น gzip พูดว่า: "โปรแกรม gzip บีบอัดและคลายไฟล์โดยใช้การเข้ารหัส Lempel-Ziv (LZ77) หากไม่มีไฟล์ที่ระบุไว้ gzip จะบีบอัดจากอินพุตมาตรฐานหรือขยายออกเป็นเอาต์พุตมาตรฐาน" หากหน้าคนไม่ได้พูดถึงอินพุตมาตรฐานมันจะไม่ใช้มัน
Alan Shutko

16

นี่เป็นคำถามที่น่าสนใจและเกี่ยวข้องกับส่วนหนึ่งของปรัชญา Unix / Linux

ดังนั้นสิ่งที่เป็นความแตกต่างระหว่างโปรแกรมเช่นgrep, sed, sortบนมือข้างหนึ่งและkill, rm, lsบนมืออื่น ๆ ? ฉันเห็นสองด้าน

กรองด้าน

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

  • โปรแกรมชนิดที่สองทำหน้าที่อินพุต แต่เอาต์พุตที่ให้มักไม่เกี่ยวข้องกับอินพุต killไม่มีเอาต์พุตเมื่อทำงานเป็นประจำและไม่lsทำงาน เพียงแค่มีค่าตอบแทนเพื่อแสดงความสำเร็จ โดยปกติแล้วพวกเขาจะไม่รับข้อมูลจาก STDIN แต่ส่วนใหญ่จะให้ผลลัพธ์กับ STDOUT

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

ความหมายด้าน

  • สำหรับกรองใส่ของพวกเขามีความหมายไม่มีความหมาย พวกเขาอ่านข้อมูลแก้ไขข้อมูลส่งออกข้อมูล ไม่สำคัญว่าจะเป็นรายการค่าตัวเลขชื่อไฟล์หรือซอร์สโค้ด HTML หรือไม่ ความหมายของข้อมูลนี้จะได้รับจากรหัสที่คุณให้กับตัวกรองเท่านั้น: regex สำหรับgrep, กฎสำหรับawkหรือโปรแกรม Perl

  • สำหรับโปรแกรมอื่น ๆ เช่นkillหรือlsการป้อนข้อมูลของพวกเขามีความหมายเป็นdenotation killคาดว่าหมายเลขกระบวนการlsคาดหวังชื่อไฟล์หรือเส้นทาง พวกเขาไม่สามารถจัดการข้อมูลโดยพลการและไม่ได้หมายถึง หลายของพวกเขาไม่จำเป็นต้องป้อนข้อมูลหรือพารามิเตอร์ใด ๆ psเช่น พวกเขาไม่ปกติอ่านจาก STDIN

หนึ่งอาจรวมสองด้านนี้: ตัวกรองคือโปรแกรมที่อินพุตไม่มีความหมายเชิงความหมายสำหรับโปรแกรม

ฉันแน่ใจว่าฉันได้อ่านเกี่ยวกับปรัชญานี้ที่ไหนสักแห่ง แต่ฉันจำไม่ได้ว่าแหล่งข้อมูลใดในขณะนี้ขออภัย หากมีบางแหล่งที่มาโปรดอย่าลังเลที่จะแก้ไข


5

ไม่มี "กฎ" เช่นนี้ บางโปรแกรมรับอินพุตจาก STDIN และบางโปรแกรมไม่ทำ หากโปรแกรมสามารถรับอินพุตจาก STDIN ก็สามารถไปป์ไลน์ได้หากไม่สามารถทำได้

ปกติคุณสามารถบอกได้ว่าโปรแกรมจะรับอินพุตหรือไม่โดยคิดว่ามันทำอะไร หากงานของโปรแกรมคือการอย่างใดจัดการเนื้อหาของไฟล์ (เช่นgrep, sed, awkฯลฯ ) มันปกติจะใช้เวลาการป้อนข้อมูลจาก STDIN หากงานของมันคือการจัดการกับไฟล์ตัวเอง (เช่นmv, rm, cp) หรือกระบวนการ (เช่นkill, lsof) หรือข้อมูลเกี่ยวกับสิ่งที่กลับมา (เช่นtop, find, ps) แล้วมันไม่ได้

วิธีคิดอีกอย่างคือความแตกต่างระหว่างการโต้แย้งและอินพุต ตัวอย่างเช่น:

mv foo bar

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

ในทางกลับกัน

sed -e 's/foo/bar/' < file
--- -- ------------   ----
 |   |       |          |-> input
 |   |       |------------> argument        
 |   |--------------------> option/flag/switch
 |------------------------> command

ที่นี่sedได้รับการป้อนข้อมูลเช่นเดียวกับการโต้แย้ง เนื่องจากใช้อินพุตจึงสามารถอ่านได้จาก STDIN และสามารถส่งไปยัง

จะได้รับความซับซ้อนมากขึ้นเมื่อมีการโต้แย้งสามารถจะป้อนข้อมูล ตัวอย่างเช่น

cat file

นี่คืออาร์กิวเมนต์ที่ได้รับไปfile catเพื่อความแม่นยำชื่อ ไฟล์fileคืออาร์กิวเมนต์ อย่างไรก็ตามเนื่องจากcatเป็นโปรแกรมที่ปรุงแต่งเนื้อหาของไฟล์, fileการป้อนข้อมูลของมันคือสิ่งที่อยู่ภายใน

สิ่งนี้สามารถถูกแสดงโดยใช้straceโปรแกรมที่ติดตามการเรียกของระบบโดยกระบวนการ หากเราทำงานcat fooผ่านstraceเราจะเห็นว่าไฟล์fooเปิดอยู่:

$ strace cat foo 2| grep foo
execve("/bin/cat", ["cat", "foo"], [/* 44 vars */]) = 0
open("foo", O_RDONLY)     

บรรทัดแรกข้างต้นแสดงให้เห็นว่าโปรแกรม/bin/catนั้นถูกเรียกใช้และข้อโต้แย้งของมันคือcatและfoo(อาร์กิวเมนต์แรกเป็นตัวโปรแกรมเสมอ) หลังจากนั้นอาร์กิวเมนต์fooถูกเปิดในโหมดอ่านอย่างเดียว ตอนนี้เปรียบเทียบกับ

$ strace ls foo 2| grep foo 
execve("/bin/ls", ["ls", "foo"], [/* 44 vars */]) = 0
stat("foo", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
lstat("foo", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
write(1, "foo\n", 4foo

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

โดยสรุปหากคำสั่งที่คุณใช้อยู่จะอ่านอินพุตคุณสามารถไพพ์ไปที่คำสั่งนั้นถ้าไม่คุณไม่สามารถทำได้


0
  • ทำไมมันไม่ทำงานกับ kill หรือ rm

killและrmไม่ต้องการ STDIN

  • อะไรคือความแตกต่างระหว่าง kill, อินพุต rm กับ grep, awk input?

สำหรับkillและrmผู้ใช้ให้ข้อมูลที่กำหนดเองของพวกเขาเป็นข้อโต้แย้งและ$(cmd)ช่วยในการ STDOUT cmdและการแปลงมันเป็นข้อโต้แย้งข้อมูล

สำหรับgrepและawkผู้ใช้ให้ข้อโต้แย้งและนอกจากนี้ยังSTDINหรือไฟล์ปกติที่จะถูกประมวลผลโดยคำสั่ง STDINสามารถส่งผ่านไปป์ไลน์|หรือโดยการป้อนข้อมูลด้วยตนเอง

  • มีกฎอะไรบ้าง?

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

เพียงแค่ป้อนคำสั่งที่คุณอยากรู้พร้อมอาร์กิวเมนต์ที่คุณเข้าใจแล้วและดูว่าคำสั่งหยุดชั่วคราว (ไม่มีอะไรเกิดขึ้น) ถ้ามันหยุดชั่วคราวมันกำลังรอ STDIN อยู่ (คุณสามารถลองcatและechoดูต่าง ๆ ) คุณพิมพ์ด้วยตนเองCtrl-Dและคำสั่งดำเนินต่อไป (แสดงผลลัพธ์หรือข้อผิดพลาด) และส่งคืน คำสั่งดังกล่าวต้องการ STDIN ในสถานการณ์นั้น (พร้อมอาร์กิวเมนต์ที่คุณระบุ)

คำสั่งเดียวกันอาจไม่ต้องการ STDIN ในสถานการณ์ที่แตกต่างกัน (เช่นcatรอ STDIN แต่cat file.txtไม่ใช่)

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