วิธีไพพ์เอาต์พุตคำสั่งไปยังคำสั่งอื่น ๆ ?


83

ตัวอย่าง:

ls | echoไม่พิมพ์อะไรเลย (บรรทัดว่างเปล่า) ฉันคาดหวังให้พิมพ์รายการไฟล์

ls | grep 'foo'ในทางกลับกันทำงานตามที่คาดไว้ (พิมพ์ไฟล์ด้วย 'foo' ในชื่อของพวกเขา)

สิ่งที่ฉันทำในสถานการณ์เหล่านี้เป็นสิ่งที่ชอบ: ls | while read OUT; do echo $OUT; doneแต่มันค่อนข้างยุ่งยาก

เหตุใดการไพพ์จึงทำงานกับคำสั่งบางอย่าง แต่ไม่ใช่กับคำสั่งอื่น? ฉันจะหลีกเลี่ยงปัญหานี้ได้อย่างไร


2
คุณคาดหวังว่าls | echoจะทำอะไร? ทำไมไม่เพียงแค่ใช้ls?
theomega

12
ฉันใช้ตัวอย่างที่ง่ายที่สุดที่แสดงจุดของฉัน ฉันประสบปัญหานี้จริง ๆ แล้วเมื่อฉันพยายามสร้างซับเดี่ยวที่จะแสดงวัตถุ git ในที่เก็บวัตถุและประเภทของวัตถุเหล่านั้น ดังนั้นฉันจึงส่ง ID วัตถุไปที่git cat-fileแต่ก็ไม่ได้ผล เห็นได้ชัดว่า echo มีพฤติกรรมเหมือนกันดังนั้นฉันจึงใช้มันเป็นตัวอย่าง
Mihai Rotaru

ดูที่คำสั่ง -n เพื่อหา xargs มันบอกว่ามีกี่อาร์กิวเมนต์ที่จะใส่คำสั่งย่อย `... | xargs -n1 git cat-file`
Rich Homolka

คำตอบ:


118

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

ls | echo

เชื่อมต่อเอาต์พุตมาตรฐานของ ls กับอินพุตมาตรฐานของ echo ใช่มั้ย echo จะละเว้นอินพุตมาตรฐานและจะดัมพ์อาร์กิวเมนต์บรรทัดคำสั่ง - ซึ่งไม่มีในกรณีนี้เพื่อ - stdout ของตัวเอง ผลลัพธ์: ไม่มีอะไรเลย

มีวิธีแก้ปัญหาบางอย่างในกรณีนี้ หนึ่งคือการใช้คำสั่งที่อ่าน stdin และทิ้งเพื่อ stdout เช่น cat

ls | cat

จะ 'ทำงาน' ขึ้นอยู่กับความหมายของงานของคุณ

แต่สิ่งที่เกี่ยวกับกรณีทั่วไป สิ่งที่คุณต้องการคือการแปลง stdout ของคำสั่งหนึ่งเป็นบรรทัดคำสั่ง args ของอีกคำสั่งหนึ่ง ดังที่คนอื่น ๆ พูดกันว่าxargsเป็นเครื่องมือตัวช่วย canonical ในกรณีนี้การอ่านบรรทัดคำสั่ง args สำหรับคำสั่งจาก stdin และการสร้างคำสั่งเพื่อเรียกใช้

ls | xargs echo

คุณสามารถแปลงบางส่วนนี้โดยใช้คำสั่งการแทนที่ $()

echo $(ls)

จะทำในสิ่งที่คุณต้องการ

เครื่องมือทั้งสองนี้เป็นแกนหลักในการเขียนสคริปต์ของเชลล์คุณควรเรียนรู้ทั้งสองอย่าง

เพื่อความสมบูรณ์ตามที่คุณระบุในคำถามวิธีอื่น ๆ ในการแปลง stdin เป็นบรรทัดคำสั่ง args คือreadคำสั่งbuiltin ของเชลล์ มันจะแปลง "words" (คำที่กำหนดโดยIFSตัวแปร) เป็นตัวแปร temp ซึ่งคุณสามารถใช้ในการรันคำสั่งใด ๆ


1
คำตอบที่ให้ข้อมูลที่เป็นประโยชน์มากขอบคุณ! ฉันกำลังเรียนรู้การทุบตีและฉันเคยเห็นทั้งเครื่องหมาย xargs และเครื่องหมาย $ (*) มาก่อน แต่ไม่ได้สนใจพวกเขามากนัก ตอนนี้ฉันรู้แล้วว่าพวกเขาสำคัญแค่ไหนและจะมองเข้าไปในพวกเขาอย่างแน่นอน
Mihai Rotaru

1
xargs อาจเป็นสิ่งที่ OP กำลังมองหา
Iktys

19

ls | echoพิมพ์เพียงบรรทัดว่างเพราะechoไม่อ่านอินพุต คำสั่งสุดท้ายของไปป์ไลน์นั้นจริง ๆ แล้วechoไม่ได้พิมพ์อะไรนอกจากบรรทัดว่าง

โดยทั่วไป:

a | b

ทำให้แน่ใจว่าการส่งออกของกลายเป็นการป้อนข้อมูลของa bผมขอแนะนำให้คุณอ่านส่วนหนึ่งของPipelinesman bash


หากคุณต้องการใช้lsและechoร่วมกันนี่เป็นตัวอย่าง (ไร้ประโยชน์สวย):

ls | xargs -L 1 echo
echo `ls`
for i in `ls` ; do echo $i ; done


3

ทำไมไม่ใช้เพียง:

echo `ls`

หรือปลอดภัยกว่ามาก:

echo "`ls -lrt`"

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