2009-10-01 23 views
6

xem xét:ống, tiêu chuẩn đầu vào và dòng lệnh lập luận trong Bash

command1 | command2 

là sản phẩm của command1 sử dụng như đầu vào tiêu chuẩn của command2 hoặc như các đối số dòng lệnh để Command2?

Ví dụ,

cat test.sh | grep "hehe" 

hình thức tương đương của nó mà không cần sử dụng một ống là bao nhiêu?

tôi đã cố gắng

grep "hehe" $(cat test.sh) 

và có vẻ như không phải là chính xác.

+1

Câu hỏi của bạn hơi khó hiểu - hy vọng chuyển hướng đầu vào hoặc chỉ đơn giản là cung cấp tên tệp làm đối số là những gì bạn muốn. Mặt khác, nếu bạn đang hỏi làm thế nào để có được stdout của một lệnh và đưa nó vào stdin của lệnh khác mà không cần sử dụng một đường ống ... đó là định nghĩa của một đường ống. – Cascabel

Trả lời

14
grep "hehe" < test.sh 

Chuyển hướng đầu vào - chỉ hoạt động cho một tệp duy nhất, tất nhiên, trong khi cat hoạt động với bất kỳ số lượng tệp đầu vào nào.


Cân nhắc các ký hiệu:

grep "hehe" $(cat test.sh) 
grep "hehe" `cat test.sh` 

Đây là tương đương trong bối cảnh này; nó là dễ dàng hơn để sử dụng '$(cmd)' ký hiệu trong sử dụng lồng nhau, chẳng hạn như:

x=$(dirname $(dirname $(which gcc))) 
x=`dirname \`dirname \\\`which gcc\\\`\`` 

(này cung cấp cho bạn các thư mục cơ sở, trong đó GCC được cài đặt, trong trường hợp bạn đang tự hỏi.)

Trong ví dụ grep, điều xảy ra là nội dung của test.sh được đọc và chia thành các từ được phân tách bằng dấu cách trắng và mỗi từ như vậy được cung cấp dưới dạng đối số cho grep. Vì grep xử lý các từ sau "hehe" (trong đó grep, tất nhiên, không không xem dấu ngoặc kép - và chúng không cần thiết trong trường hợp này, như một quy tắc chung, sử dụng dấu nháy đơn chứ không phải dấu ngoặc kép, đặc biệt là xung quanh các chuỗi phức tạp như cụm từ thông dụng thường sử dụng các siêu ký tự shell) ... Như tôi đã nói, grep xử lý các từ sau "hehe" làm tên tệp và cố gắng mở từng tệp, thường không thất bại do tệp không tồn tại. Đây là lý do tại sao ký pháp không phù hợp trong ngữ cảnh này.


Sau khi xem lại câu hỏi, có thể nói nhiều hơn - điều đó chưa được nói.

Trước hết, nhiều lệnh Unix được thiết kế để hoạt động như 'bộ lọc'; họ đọc đầu vào từ một số tệp, chuyển đổi nó theo một cách nào đó và ghi kết quả vào đầu ra tiêu chuẩn. Các lệnh như vậy được thiết kế để sử dụng trong các đường dẫn lệnh. Ví dụ như:

  • mèo
  • grep
  • troff và người thân
  • awk (với hãy cẩn thận)
  • sed
  • loại

Tất cả các bộ lọc này có hành vi chung giống nhau : họ có các tùy chọn dòng lệnh để kiểm soát hành vi của họ và sau đó họ đọc tệp s được chỉ định làm đối số dòng lệnh hoặc, nếu không có đối số như vậy, chúng sẽ đọc đầu vào chuẩn của chúng. Một số (như sort) có thể có các tùy chọn để kiểm soát nơi đầu ra của chúng đi thay vì đầu ra tiêu chuẩn, nhưng điều đó tương đối không phổ biến.

Có một vài bộ lọc tinh khiết - tr là một bộ lọc như vậy - đầu vào tiêu chuẩn đọc kỹ và ghi vào đầu ra tiêu chuẩn.

Các lệnh khác có các hành vi khác nhau. Eric Raymond cung cấp phân loại cho các loại lệnh trong "The Art of UNIX Programming".

Một số lệnh tạo danh sách tên tệp trên đầu ra tiêu chuẩn - hai tác phẩm kinh điển là lsfind.

Đôi khi, bạn muốn áp dụng đầu ra từ trình tạo tên tệp làm đối số dòng lệnh cho bộ lọc. Có một chương trình tự động thực hiện - đó là xargs.

cổ điển, bạn sẽ sử dụng:

find . -name '*.[chyl]' | xargs grep -n magic_name /dev/null 

Điều này sẽ tạo ra một danh sách đầy đủ các tập tin với phần mở rộng '.c', '.h', '.y' và '.l' (nguồn C, tiêu đề, Yacc và các tệp Lex). Vì danh sách được đọc bởi xargs, nó sẽ tạo các dòng lệnh với grep -n magic_name /dev/null khi bắt đầu và mỗi từ (được phân tách bằng dấu cách trắng) làm đối số.

Trong những ngày cũ, tên tệp Unix không bao gồm dấu cách. Dưới ảnh hưởng của Mac và Windows, các không gian như vậy giờ đã trở nên phổ biến. Các phiên bản GNU của findxargs có các tùy chọn bổ sung để đối phó với vấn đề này:

find . -name '*.[chyl]' -print0 | xargs -0 grep -n magic_name /dev/null 

Các '-print0' tùy chọn có nghĩa là "tên file in chấm dứt bởi một NUL '\ 0'" (vì các nhân vật duy nhất có thể không xuất hiện trong một tên tập tin (đơn giản) là '/' và NUL, và rõ ràng, '/' có thể xuất hiện trong tên đường dẫn). Tương ứng '-0' yêu cầu xargs tìm tên được chấm dứt bằng NUL thay vì tên cách nhau bằng dấu cách.

+0

Chuyển hướng đầu vào có cung cấp đầu vào stdin hoặc đối số dòng lệnh cho grep không? – Tim

+0

Thực ra câu hỏi của tôi là cho lệnh chung hơn là chỉ cho grep. – Tim

+0

Vì vậy, tôi thấy, sau khi làm sạch nó ... và tôi đã khái quát câu trả lời của tôi: D –

1

Nó được sử dụng làm tiêu chuẩn.

Hãy thử:

grep "hehe" - $(cat test.sh) 

Đó có thể là sai; Tôi không thể kiểm tra nó trên máy tính này. Nếu bạn làm điều đó mà không có đường ống như bạn đã thử, grep xử lý đối số cuối cùng dưới dạng tên tệp, nghĩa là tìm kiếm một tệp có tên [nội dung của test.sh]. Nếu bạn vượt qua nó a - (hoặc không đặt một đối số cuối cùng), bạn nói với nó để sử dụng stdin như tập tin.

Bạn cũng có thể chỉ cần vượt qua grep một file để quét qua:

grep "hehe" test.sh 

... nhưng bạn dường như được hỏi thêm một câu hỏi bash tổng quát, chứ không phải thực sự là một câu hỏi sử dụng grep, do đó có lẽ không phải quá hữu ích.

+0

Mất mỗi từ trong test.sh và tìm kiếm một tệp có cùng tên với từ đó và tìm kiếm các tệp đó (thường có thành công rất hạn chế). –

+0

Các backticks là thay thế lệnh giống như '$()', chỉ cần không có tổ chức và dễ dàng hơn để mess up. Dạng thứ hai có lẽ là những gì Tim đang tìm kiếm. – Cascabel

+0

Tôi nhận ra rằng; Tôi đã chỉnh sửa rồi. : P –

6

Một hình thức chuyển hướng khác là quá trình thay thế.

grep "hehe" <(cat test.sh) 

tương đương với:

grep "hehe" test.sh 

mà cả hai nhìn vào các nội dung của test.sh riêng của mình.

Trong khi, vì nó đã được ghi nhận, lệnh này:

grep "hehe" $(cat test.sh) 

tìm kiếm tên tập tin trong test.sh và sử dụng chúng như các đối số cho grep. Vì vậy, nếu test.sh gồm:

scriptone 
scripttwo 

sau đó grep sẽ tìm kiếm "hehe" trong nội dung của mỗi người trong số các tập tin.

+2

Tôi không thích sử dụng của bạn là 'tương đương' trên dòng 3: 'grep" hehe "test.sh' là, cuối cùng, bằng cách sử dụng nội dung của test.sh như stdin trong khi' grep "hehe" <(cat test. sh) 'đang sử dụng đầu ra của lệnh' cat test.sh' làm stdin. Hãy xem xét sự khác biệt trong kết quả nếu bạn chạy các lệnh như sau: 'grep -H" hehe "<(cat test.sh)' và 'grep -H" hehe "test.sh' –

1

Tương đương với đường ống bash bằng các đối số dòng lệnh là gì?

Đối số đường ống và dòng lệnh là các hình thức đầu vào khác nhau không thể hoán đổi cho nhau. Nếu một chương trình cho phép bạn có các hình thức tương đương của cả hai, đó là sự lựa chọn của chương trình đó một mình. (Trong mã nguồn, các đối số dòng lệnh xuất hiện dưới dạng văn bản trong một biến, trong khi các đường dẫn xuất hiện dưới dạng các tệp mở, bao gồm cả stdin và stdout. Cú pháp chuyển hướng I/O Bash, như được sử dụng ở đây, về mặt kỹ thuật, không mặc dù được viết ngay bên cạnh họ trên dòng lệnh ...)

Nhưng chúng ta hãy pedantic và cũng trả lời này:

tương đương với một ống bash mà không sử dụng một nhân vật ống bash là gì?

Trả lời: cat test.sh | grep "hehe" tương đương với

grep "hehe" < <(cat test.sh) 

Giải thích:

  • Ống chuyển hướng stdout của một lệnh để stdin của người khác. Để thiết lập nguồn stdin, chúng ta có thể sử dụng chuyển hướng đầu vào (< …) thay vì sử dụng ký tự ống.
  • Tuy nhiên, chỉ sử dụng chuyển hướng đầu vào (grep "hehe" < test.sh) không phải là tương đương với ống vì nó sử dụng một tập tin như là nguồn cho stdin, trong khi ống sử dụng đầu ra một lệnh (cat test.sh). Vì vậy, ngoài ra, chúng tôi thêm quá trình thay thế <(…) để thay thế đầu vào từ một tệp có đầu vào từ một lệnh.
  • Tất nhiên, ví dụ này là khó hiểu bởi vì hai biến thể có những tác động giống nhau:

    grep "hehe" < test.sh 
    grep "hehe" < <(cat test.sh) 
    

    Nhưng về mặt kỹ thuật, đầu vào từ một tập tin vẫn còn là một cơ chế khác so với đầu vào từ đầu ra của một lệnh mà được nó đầu vào từ một tệp.

Nguồn: Advanced Bash Scripting Manual, section on process substitution (bắt đầu đọc tại "Một số cách sử dụng khác").

Các vấn đề liên quan