ทำความเข้าใจถึงวิธีการที่อินพุตถูกส่งไปยังไพพ์ใน Bash


17

ฉันไม่ค่อยเข้าใจว่าท่อทำงานอย่างไรในการทุบตี

ฉันรู้ว่ามันใช้เอาต์พุตจากคำสั่งหนึ่งเป็นอินพุตในคำสั่งอื่น

สิ่งที่ฉันจะได้รับเอาท์พุทเพราะมันเป็นสิ่งที่คำสั่งพิมพ์ออกมาที่หน้าจอ

แต่ฉันจะรู้ได้อย่างไรว่าคำสั่งอินพุตใดที่จะใช้?

นี่คือตัวอย่างที่ฉันคิดว่าน่าจะใช้ได้:

which gem | rm

น่าเสียดายที่มันไม่ได้

อัญมณีชนิดใดที่พิมพ์ออกมา/usr/bin/gemเพื่อที่จะต้องได้ผลลัพธ์ที่ถูกต้อง?

ฉันคิดว่ามันถูกมอบให้กับ rm ดังนั้นมันจึงเป็นไปได้rm /usr/bin/gemแต่ฉันคิดผิด

ดังนั้นคำถามของฉันคือฉันจะรู้ได้อย่างไรว่าคำสั่งอินพุตใช้อย่างไร


2
นอกเหนือจากสิ่งอื่นrm /usr/bin/gemเป็นความคิดที่น่ากลัว ปล่อยให้gem(และล่าม Ruby มาด้วย) เพียงอย่างเดียวและติดตั้งล่าม Ruby ที่คุณต้องการ (และgem) โดยใช้rvm: rvm.beginrescueend.com
Telemachus

คำตอบ:


23

"อินพุต" และ "อาร์กิวเมนต์บรรทัดคำสั่ง" เป็นสิ่งที่แตกต่างกัน

rm ลบไฟล์ที่มีให้เป็นอาร์กิวเมนต์

ไพพ์เปลี่ยนทิศทางเอาต์พุตของคำสั่งซ้ายไปยังอินพุตของคำสั่งขวามือ ไม่มีผลต่ออาร์กิวเมนต์บรรทัดคำสั่งของโปรแกรมทางด้านขวา

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

which gem | xargs rmตัวอย่างเช่นจะลบเครื่องหมายgemใน PATH ของคุณ


12

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

grep "foo" file.txt

มีสองข้อโต้แย้งที่มีและ"foo" อินพุตเป็นเนื้อหาของไม่สตริงเอง เนื่องจาก grep รับอินพุตคุณสามารถใช้กับท่อ:file.txtfile.txtfile.txt

cat file.txt | grep "foo"

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

หากคุณต้องการใช้เอาต์พุตของหนึ่งโปรแกรมเป็นอาร์กิวเมนต์ให้กับอีกโปรแกรมหนึ่งคุณใช้ backticks:

rm `which gem`

หรือไวยากรณ์ทางเลือก (เฉพาะสำหรับ bash) นี้:

rm $(which gem)

แก้ไข: หรือxargsเป็นผู้ตอบคนอื่นชี้ให้เห็น มีหลายวิธีในการสกินแมวด้วยบรรทัดคำสั่ง


มันน่าสังเกตว่าอาจจะเป็นหลายร้อยครั้งช้ากว่าcat file.txt | grep "foo" grep "foo" file.txt
Borealid

1
นี่คือส่วนที่ฉันไม่เข้าใจ ฉันจะรู้ได้อย่างไรว่าอาร์กิวเมนต์คืออะไรและอินพุตมาตรฐานคืออะไร
ajsie

8
@ajsie: หากคุณพิมพ์หลังชื่อโปรแกรมและก่อนกด Enter จะเป็นข้อโต้แย้ง หากคุณพิมพ์ลงในโปรแกรมหลังจากที่เริ่มทำงานมันเป็นอินพุตมาตรฐาน
Borealid

1
เข้าใจแล้ว! สิ่งนี้อธิบายทุกอย่าง ตอนนี้ฉันรู้ว่าฉันทั้งสองสามารถใช้คำสั่งโดยตรงและดูว่ามันแจ้งให้ฉัน (grep) และฉันยังสามารถอ่านคู่มือ (man grep) เพื่อดูว่ามันใช้ std อินพุต
ajsie

@ajsie: หากคุณไม่ต้องการดำดิ่งลงไปใน manpage ก็จะได้grep --helpรับภาพรวมของข้อโต้แย้งที่ยอมรับได้เช่นกัน
Borealid

3

ลองดูmanหน้าคำสั่งที่คุณสนใจโปรแกรมเหล่านี้จะระบุว่าพวกเขาอ่านจากstdin(ลองman grepคำสั่งยอดนิยมที่อ่าน stdin)


ฉันพยายามman grep | grep 'standard input'และได้รับIf no file arguments are specified, the standard input is used.เป็นนัดสุดท้าย 👍ฉันต้องให้grepยาของตัวเองเล็กน้อย 😎
ma11hew28

2

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

rm `which gem`       # Dangerous
rm $(which gem)      # Dangerous
which gem | xargs rm # Dangerous

GNU Parallel http: // www.gnu.org/software/parallel/ ไม่มีปัญหาดังกล่าวดังนั้นสิ่งนี้จะใช้ได้แม้ว่าคุณจะมีไดเรกทอรีใน PATH ของคุณที่มีช่องว่างหรือถ้าชื่อคำสั่งมีช่องว่าง:

which gem | parallel rm
parallel -a <(which bass) rm

ดูวิดีโอแนะนำสำหรับ GNU Parallel: http://www.youtube.com/watch?v=OpaiGYxkSuQ

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