การใช้ข้อมูลที่อ่านจากไพพ์แทนที่จะเป็นไฟล์ในตัวเลือกคำสั่ง


18

ตามนิยามของมนุษย์คำสั่งนี้รับอินพุตจากไฟล์

$ command -r FILENAME

สมมติว่าเป็นไฟล์ที่มีรายชื่อของชื่อไฟล์เป็นมันถูกสร้างขึ้นโดยใช้FILENAMEls > FILENAME

ฉันจะป้อนคำสั่งด้วยผลลัพธ์lsโดยตรงได้อย่างไร ในหัวของฉันบางสิ่งเช่นนี้น่าจะเป็นไปได้:

$ ls | command -r

แต่ไม่เช่นนั้นผลลัพธ์ของการlsไม่ได้รับการเชื่อมต่อเป็นอาร์กิวเมนต์ เอาท์พุท:

Usage: command -r FILENAME
error: -r option requires an argument

ฉันจะได้รับผลที่ต้องการได้อย่างไร


คำตอบเพิ่มเติมเกี่ยวกับสิ่งนี้ในคำถามที่เกี่ยวข้อง: วิธีส่งสตริงไปยังคำสั่งที่ต้องการไฟล์ได้อย่างไร
ilkkachu

คำตอบ:


31

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

  • คำสั่งจำนวนมากถือว่า-เป็นชื่อพิเศษหมายถึงอ่านจากอินพุตมาตรฐานแทนที่จะเปิดไฟล์ นี่คือการประชุมไม่ใช่ข้อผูกมัด

    ls | command -r -
  • หลายตัวแปรยูนิกซ์ให้ไฟล์พิเศษใน/devที่กำหนด descriptor มาตรฐาน หาก/dev/stdinมีอยู่ให้เปิดและอ่านจากมันเทียบเท่ากับการอ่านจากอินพุตมาตรฐาน เช่นเดียวกัน/dev/fd/0หากมีอยู่

    ls | command -r /dev/stdin
    ls | command -r /dev/fd/0
  • หากเชลล์ของคุณคือ ksh, bash หรือ zsh คุณสามารถสร้างเชลล์จัดการกับธุรกิจของการจัดสรรไฟล์ descriptor บางตัว ข้อดีหลักของวิธีนี้คือมันไม่ได้เชื่อมโยงกับอินพุตมาตรฐานดังนั้นคุณสามารถใช้อินพุตมาตรฐานสำหรับอย่างอื่นและคุณสามารถใช้ได้มากกว่าหนึ่งครั้ง

    command -r <(ls)
  • หากคำสั่งคาดว่าชื่อจะมีรูปแบบเฉพาะ (โดยปกติจะเป็นส่วนขยายเฉพาะ) คุณสามารถลองหลอกมันด้วยลิงก์สัญลักษณ์

    ln -s /dev/fd/0 list.foo
    ls | command -r list.foo

    หรือคุณสามารถใช้ไพพ์ที่มีชื่อ

    mkfifo list.foo
    ls >list.foo &
    command -r list.foo

โปรดทราบว่าการสร้างรายการไฟล์ที่มีlsปัญหาเนื่องจากlsมีแนวโน้มที่จะรวมชื่อไฟล์เมื่อมีอักขระที่ไม่สามารถพิมพ์ได้ printf '%s\n' *มีความน่าเชื่อถือมากขึ้น - มันจะพิมพ์ทุกไบต์อย่างแท้จริงในชื่อไฟล์ ชื่อไฟล์ที่มีการขึ้นบรรทัดใหม่จะยังคงมีปัญหา แต่ก็ไม่สามารถหลีกเลี่ยงได้หากคำสั่งคาดหวังรายการของชื่อไฟล์ที่คั่นด้วยการขึ้นบรรทัดใหม่


+1 สำหรับแจกแจงความเป็นไปได้ทั้งหมด การทดแทนกระบวนการ IMO เป็นคำตอบที่ถูกต้องสำหรับสถานการณ์นี้
เกล็นแจ็คแมน

7

มันควรจะเป็น:

ls | xargs -n 1 command -r

แก้ไข: สำหรับชื่อที่มีช่องว่าง:

ls | xargs -d '\n' -n 1 command -r

นี่อาจเป็นปัญหาได้หากcommandเชื่อว่ามีชื่อไฟล์ทั้งหมดที่จำเป็นในบรรทัดคำสั่งทั้งหมดพร้อมกัน xargs บางรุ่นจะให้commandชื่อไฟล์สองสามรายการ (ครั้งละ 10 ชื่อสำหรับฉัน) ดูเหมือนว่า GNU xargs ให้ทุกอย่างพร้อมกัน
Bruce Ediger

2

จริงๆแล้วทางออกเดียวที่เชื่อถือได้ที่ฉันรู้ว่าสามารถจัดการชื่อไฟล์ทั้งหมดรวมถึงที่มีบรรทัดใหม่ในพวกเขาคือ:

find . -maxdepth 1 -print0 | xargs -n 1 -0 command -r

อักขระที่ไม่อนุญาตเฉพาะในชื่อไฟล์ในกรณีนี้คือตัวอักษร null ซึ่งไม่อนุญาตให้ใช้ในชื่อไฟล์อย่างไรก็ตาม


1

คำสั่งจำนวนมากยอมรับ-ว่าเป็น "ชื่อไฟล์" ซึ่งหมายถึง "ใช้อินพุตมาตรฐาน" แต่การประชุมนี้อยู่ไกลจากสากล อ่าน man page


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