Sử dụng dữ liệu đọc từ một đường ống thay vì từ một tệp trong các tùy chọn lệnh


18

Theo định nghĩa của mỗi người, lệnh này nhận đầu vào từ một tệp.

$ command -r FILENAME

Giả sử đó FILENAMElà một tệp chứa danh sách tên tệp, vì nó được tạo bằng cách sử dụng ls > FILENAME.

Thay vào đó, làm thế nào tôi có thể cung cấp lệnh với kết quả lstrực tiếp? Trong đầu tôi một cái gì đó như thế này nên có thể:

$ ls | command -r

Nhưng nó không, đầu ra của lskhông được nối như là một đối số. Đầu ra:

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

Làm thế nào tôi có thể có được hiệu quả mong muốn?


Nhiều câu trả lời hơn về vấn đề này trong một câu hỏi liên quan: Làm thế nào để truyền một chuỗi vào một lệnh mong đợi một tệp?
ilkkachu

Câu trả lời:


31

Điều này phụ thuộc vào lệnh. Một số lệnh đọc từ tệp mong muốn tệp đó là tệp thông thường, có kích thước được biết trước và có thể được đọc từ bất kỳ vị trí nào và được tua lại. Điều này là không thể nếu nội dung của tệp là một danh sách các tên tệp: thì lệnh có thể sẽ là nội dung với một đường ống mà nó sẽ chỉ đọc tuần tự từ đầu đến cuối. Có một số cách để cung cấp dữ liệu thông qua một đường ống đến một lệnh mong đợi một tên tệp.

  • Nhiều lệnh coi -như một tên đặc biệt, có nghĩa là đọc từ đầu vào tiêu chuẩn thay vì mở tệp. Đây là một quy ước, không phải là một nghĩa vụ.

    ls | command -r -
  • Nhiều biến thể unix cung cấp các tệp đặc biệt trong /devđó chỉ định các mô tả chuẩn. Nếu /dev/stdintồn tại, mở nó và đọc từ nó tương đương với đọc từ đầu vào tiêu chuẩn; tương tự như vậy /dev/fd/0nếu nó tồn tại.

    ls | command -r /dev/stdin
    ls | command -r /dev/fd/0
  • Nếu shell của bạn là ksh, bash hoặc zsh, bạn có thể thực hiện giao dịch shell với doanh nghiệp phân bổ một số mô tả tệp. Ưu điểm chính của phương pháp này là nó không bị ràng buộc với đầu vào tiêu chuẩn, vì vậy bạn có thể sử dụng đầu vào tiêu chuẩn cho một thứ khác và bạn có thể sử dụng nó nhiều lần.

    command -r <(ls)
  • Nếu lệnh mong muốn tên có một hình thức cụ thể (thường là một phần mở rộng cụ thể), bạn có thể thử đánh lừa nó bằng một liên kết tượng trưng.

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

    Hoặc bạn có thể sử dụng một đường ống được đặt tên.

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

Lưu ý rằng việc tạo danh sách các tệp có lsvấn đềlscó xu hướng xáo trộn tên tệp khi chúng chứa các ký tự không thể in được. printf '%s\n' *đáng tin cậy hơn - nó sẽ in từng byte theo nghĩa đen trong tên tệp. Tên tệp chứa dòng mới vẫn sẽ gây rắc rối, nhưng điều đó là không thể tránh khỏi nếu lệnh mong đợi một danh sách tên tệp được phân tách bằng dòng mới.


+1 để liệt kê tất cả các khả năng. Thay thế quá trình IMO là câu trả lời chính xác cho tình huống này.
glenn jackman

7

Nó nên là:

ls | xargs -n 1 command -r

Chỉnh sửa: cho tên có khoảng trắng:

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

Điều này có thể có vấn đề nếu commandtin rằng nó có tất cả các tên tệp mà nó sẽ cần trên dòng lệnh cùng một lúc. Một số phiên bản của xargs sẽ cung cấp commandmột vài tên tệp (10, có vẻ như đối với tôi) tại một thời điểm. Có vẻ như GNU xargs cung cấp tất cả mọi thứ cùng một lúc.
Bruce Ediger

2

Trên thực tế, giải pháp đáng tin cậy duy nhất mà tôi biết có thể xử lý tất cả tên tệp, bao gồm cả những tên có dòng mới trong đó, là:

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

Ký tự không được phép duy nhất trong tên tệp trong trường hợp này là ký tự null, dù sao không được phép trong tên tệp.


1

Nhiều lệnh chấp nhận -là "tên tệp" có nghĩa là "sử dụng đầu vào tiêu chuẩn", nhưng quy ước này không phải là phổ quát. Đọc trang người đàn ông.


1

Điều này sẽ làm việc cho mục đích của bạn: ls | command -r /dev/stdin

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.