2011-08-01 104 views
12

Khi tôi làmTại sao ps o/p liệt kê quy trình grep sau đường ống?

$ ps -ef | grep cron 

tôi nhận được

root  1036  1 0 Jul28 ?  00:00:00 cron 
abc 21025 14334 0 19:15 pts/2 00:00:00 grep --color=auto cron 

Câu hỏi của tôi là tại sao tôi thấy dòng thứ hai. Từ sự hiểu biết của tôi, ps liệt kê các quy trình và đưa đường ống vào danh sách theo số grep. grep thậm chí không bắt đầu chạy trong khi ps là quá trình danh sách, sau đó làm thế nào đến quá trình grep được liệt kê trong o/p?

liên quan câu hỏi thứ hai:

Khi tôi làm

$ ps -ef | grep [c]ron 

tôi nhận được chỉ

root  1036  1 0 Jul28 ?  00:00:00 cron 

sự khác biệt giữa đầu tiên và thứ hai grep hành là gì?

+2

Bạn sẽ ngạc nhiên về kết quả của 'giấc ngủ 3 | ngủ 3 | sleep 3' ;-) – Alfe

Trả lời

13

Khi bạn thực hiện lệnh:

ps -ef | grep cron 

vỏ bạn đang sử dụng

(... tôi giả bash trong trường hợp của bạn, do thuộc tính màu sắc của grep Tôi nghĩ bạn đang chạy một hệ thống gnu như một bản phân phối Linux, nhưng nó cũng giống nhau trên unix/shell khác ...)

sẽ thực hiện cuộc gọi pipe() để tạo FIFO, sau đó nó sẽ fork() (tạo bản sao đang chạy của chính nó). Điều này sẽ tạo ra một tiến trình con mới. Quy trình con mới được tạo ra này sẽ close() bộ mô tả tệp đầu ra tiêu chuẩn của nó (fd 1) và đính kèm fd 1 vào bên ghi của đường ống được tạo bởi tiến trình cha (vỏ mà bạn đã thực hiện lệnh). Điều này là có thể bởi vì các syscall fork() sẽ duy trì, đối với mỗi, một mô tả tập tin mở hợp lệ (các fd ống trong trường hợp này). Sau khi làm như vậy, bạn sẽ thấy exec() lệnh đầu tiên (trong trường hợp của bạn) là ps được tìm thấy trong biến môi trường PATH của bạn. Với cuộc gọi exec(), quá trình sẽ trở thành lệnh bạn đã thực hiện.

Vì vậy, bây giờ bạn có quy trình trình bao với một đứa trẻ, trong trường hợp của bạn, lệnh ps có thuộc tính -ef.

Tại thời điểm này, cha (vỏ) fork() s lại. Quy trình con mới được tạo ra close() s bộ mô tả tệp đầu vào tiêu chuẩn của nó (fd 0) và gắn fd 0 vào bên đọc của đường ống được tạo bởi tiến trình cha (vỏ mà bạn đã thi hành lệnh).

Sau khi thực hiện điều đó, exec() lệnh đầu tiên (trong trường hợp của bạn) grep được tìm thấy trong biến môi trường PATH của bạn.

Bây giờ bạn có quá trình shell với hai đứa con (đó là anh chị em ruột), nơi đầu tiên là các lệnh ps với -ef thuộc tính và điều thứ hai là lệnh grep với thuộc tính cron.Mặt đọc của đường ống được gắn vào STDIN của lệnh grep và mặt ghi được gắn vào STDOUT của lệnh ps: đầu ra tiêu chuẩn của lệnh ps được đính kèm với đầu vào chuẩn của lệnh grep.

ps được viết để gửi thông tin đầu ra tiêu chuẩn trên mỗi quy trình đang chạy, trong khi grep được ghi để nhập tiêu chuẩn đầu vào tiêu chuẩn phải khớp với mẫu nhất định, bạn sẽ có câu trả lời cho câu hỏi đầu tiên của mình:

  1. chạy shell: ps -ef;
  2. vỏ chạy: grep cron;
  3. ps gửi dữ liệu (mà thậm chí có chứa chuỗi "grep cron") để grep
  4. grep khớp với mẫu tìm kiếm của nó từ STDIN và nó khớp với chuỗi "grep cron" vì thuộc tính "cron" bạn đã chuyển đến grep: bạn đang hướng dẫn grep để khớp với chuỗi "cron" và nó có nghĩa là "grep cron" là một chuỗi được trả về bởi ps tại thời điểm grep đã bắt đầu thực hiện.

Khi bạn thực hiện:

ps -ef | grep '[c]ron' 

thuộc tính thông qua chỉ thị grep để phù hợp với một cái gì đó có chứa "c" tiếp theo là "ron". Giống như ví dụ đầu tiên, nhưng trong trường hợp này nó sẽ phá vỡ chuỗi trận đấu trở lại bởi ps vì:

  1. chạy shell: ps -ef;
  2. vỏ chạy: rep [c]ron;
  3. ps gửi dữ liệu (mà thậm chí chứa chuỗi grep [c]ron) tới grep
  4. grep không khớp với mẫu tìm kiếm của nó từ stdin vì chuỗi chứa "c" theo sau "ron" không tìm thấy, nhưng đã tìm thấy chuỗi chứa "c" theo sau "] ron"

GNU grep không có giới hạn đối sánh chuỗi và trên một số nền tảng (tôi nghĩ Solaris, HPUX, aix) giới hạn chuỗi được đưa ra bởi biến "$ COLUMN" hoặc chiều rộng màn hình của thiết bị đầu cuối.

Hy vọng phản hồi dài này sẽ làm rõ quy trình ống vỏ một chút.

TIP:

ps -ef | grep cron | grep -v grep 
+0

Cảm ơn bạn đã xây dựng câu trả lời của @Ben Jackson. – abc

6

Vỏ tạo đường ống của bạn với một loạt các cuộc gọi fork(), pipe()exec(). Tùy thuộc vào vỏ bất kỳ phần nào của nó có thể được xây dựng đầu tiên. Vì vậy, grep có thể đã chạy trước ps thậm chí bắt đầu. Hoặc, ngay cả khi ps bắt đầu đầu tiên nó sẽ được ghi vào bộ đệm hạt nhân 4k và cuối cùng sẽ chặn (trong khi in một dòng đầu ra quy trình) cho đến khi grep khởi động và bắt đầu tiêu thụ dữ liệu trong đường ống. Trong trường hợp thứ hai nếu ps có thể bắt đầu và kết thúc trước grep ngay cả khi bắt đầu, bạn có thể không thấy số grep cron ở đầu ra. Bạn có thể đã nhận thấy điều này không xác định tại chơi đã.

+0

Nếu các khối ps thì danh sách sẽ không chứa grep..correct. Nhưng Ignacio dường như gợi ý rằng grep phải chạy. Tôi hơi bối rối. – abc

+0

Tôi đã thực sự không nhìn thấy sự không xác định mà bạn đề cập đến! Nhưng nó là khá thú vị để lưu ý rằng. – abc

1

câu hỏi thực tế của bạn đã được trả lời bởi những người khác, nhưng tôi sẽ đưa ra một lời khuyên: Nếu bạn muốn tránh nhìn thấy quá trình grep được liệt kê, bạn có thể làm theo cách này:

$ ps -ef | grep [c]ron 
+0

Cảm ơn nhưng tôi đã nghi ngờ thêm, về các câu trả lời dưới đây. Vui lòng xem nhận xét của tôi. – abc

+0

Tại sao sử dụng grep [c] ron không liệt kê tiến trình grep, trong khi sử dụng grep cron luôn liệt kê tiến trình grep? Hiệu ứng của biểu thức khung là gì. Bạn có thể vui lòng xây dựng? – abc

+3

@abc Nó hoạt động vì biểu thức chính quy 'grep' khớp chính xác' c' theo sau là 'ron', nhưng đầu ra' ps' sẽ hiển thị nghĩa đen 'grep [c] ron' vì đó là lệnh được nhập vào. Do đó, biểu thức 'grep' không khớp với nó và lọc nó ra. –

8

Trong lệnh của bạn

ps -ef | grep 'cron' 

Linux đang thực hiện lệnh "grep" trước lệnh ps -ef. Sau đó Linux ánh xạ đầu ra tiêu chuẩn (STDOUT) của "ps -ef" vào đầu vào tiêu chuẩn (STDIN) của lệnh grep.

Nó không thực hiện lệnh ps, lưu trữ kết quả trong bộ nhớ và chuyển chúng vào grep. Hãy nghĩ về điều đó, tại sao phải không? Hãy tưởng tượng nếu bạn đang đường ống một trăm gigabyte dữ liệu?

Chỉnh sửa liên quan đến câu hỏi thứ hai của bạn:

Trong grep (và hầu hết các động cơ biểu thức chính quy), bạn có thể xác định dấu ngoặc để cho nó biết rằng bạn sẽ chấp nhận bất kỳ nhân vật trong dấu ngoặc đơn. Vì vậy, viết [c] có nghĩa là nó sẽ chấp nhận bất kỳ charcter nào, nhưng chỉ c được xác định. Tương tự, bạn có thể thực hiện bất kỳ tổ hợp ký tự nào khác.

ps aux | grep cron 
root  1079 0.0 0.0 18976 1032 ?  Ss Mar08 0:00 cron 
root  23744 0.0 0.0 14564 900 pts/0 S+ 21:13 0:00 grep --color=auto cron 

^Đó là phù hợp với bản thân, bởi vì lệnh của riêng bạn chứa "cron"

ps aux | grep [c]ron 
root  1079 0.0 0.0 18976 1032 ?  Ss Mar08 0:00 cron 

Đó phù hợp với cron, vì cron chứa c, và sau đó "ron". Nó không phù hợp với yêu cầu của bạn tuy nhiên, vì yêu cầu của bạn là [c] ron

Bạn có thể đặt bất cứ điều gì bạn muốn trong dấu ngoặc, miễn là nó có chứa các c:

ps aux | grep [cbcdefadq]ron 
root  1079 0.0 0.0 18976 1032 ?  Ss Mar08 0:00 cron 

Nếu bạn loại bỏ C , nó sẽ không phù hợp mặc dù, bởi vì "cron", bắt đầu với ac:

ps aux | grep [abedf]ron 

^không có kết quả

chỉnh sửa 2

Để nhắc lại điểm, bạn có thể làm đủ mọi thứ điên rồ với grep. Không có ý nghĩa trong việc chọn nhân vật đầu tiên để làm điều này với.

ps aux | grep [c][ro][ro][n] 
root  1079 0.0 0.0 18976 1032 ?  Ss Mar08 0:00 cron 
+0

Tôi vừa thêm một phần nữa vào câu hỏi. Nó xảy ra với tôi rằng thật khó để đọc "ghi chú tiền thưởng". Cảm ơn. – abc

+0

Ben Jackson (bên dưới) dường như gợi ý rằng ps có thể chạy trước grep và ghi dữ liệu vào một đường ống nhân. – abc

+0

Theo như tôi biết, cái nào bắt đầu trước hết là không liên quan. Hệ điều hành không nhất thiết phải phân bổ bất kỳ thời gian CPU nào cho chúng cho đến khi STDOUT của PS được ánh xạ tới STDIN của GREP. – GoldenNewby

1

Bạn viết: "Từ sự hiểu biết của tôi, ps liệt kê các quá trình và ống dẫn danh sách để grep grep đã thậm chí không bắt đầu chạy trong khi ps được niêm yết quy trình.".

Hiểu biết của bạn không chính xác.

Đó không phải là cách hoạt động của đường ống. Vỏ không không chạy lệnh đầu tiên để hoàn thành, hãy nhớ đầu ra của lệnh đầu tiên, sau đó sau đó chạy lệnh tiếp theo bằng cách sử dụng dữ liệu đó làm đầu vào. Không.Thay vào đó, cả hai quy trình thực thi và đầu vào/đầu ra của chúng là được kết nối. Như Ben Jackson đã viết, không có gì đặc biệt đảm bảo rằng các quá trình chạy cùng một lúc, nếu cả hai đều rất ngắn ngủi và nếu hạt nhân có thể quản lý một cách thoải mái lượng dữ liệu nhỏ đi qua kết nối. Trong trường hợp đó, nó thực sự có thể xảy ra theo cách bạn mong đợi, chỉ một cách tình cờ. Nhưng mô hình khái niệm cần ghi nhớ là chúng chạy song song.

Nếu bạn muốn các nguồn chính thức, làm thế nào về trang bash người đàn ông:

A pipeline is a sequence of one or more commands separated by the character |. The format for a pipeline is: 

     [time [-p]] [ ! ] command [ | command2 ... ] 

    The standard output of command is connected via a pipe to the standard input of command2. This connection is 
    performed before any redirections specified by the command (see REDIRECTION below). 

    ... 

    Each command in a pipeline is executed as a separate process (i.e., in a subshell). 

Đối với câu hỏi thứ hai của bạn (mà không thực sự liên quan ở tất cả, Tôi rất tiếc phải nói), bạn có chỉ mô tả tính năng của cách biểu thức chính quy hoạt động. Cụm từ thông dụng cron khớp với chuỗi cron. Cụm từ thông dụng [c]ron không không khớp với chuỗi [c]ron. Do đó lệnh grep đầu tiên sẽ tự tìm thấy trong danh sách quy trình, nhưng lệnh thứ hai sẽ không.

0
$ ps -ef | grep cron 

Linux Shell luôn thực hiện lệnh từ phải sang trái. Vì vậy, trước khi thực thi ps -ef grep cron đã được thực hiện đó là lý do tại sao o/p hiển thị lệnh của chính nó.

$ ps -ef | grep [c]ron 

Nhưng trong u này chỉ định grep ron theo sau là chỉ c. do đó, o/p không có dòng lệnh vì trong lệnh có [c] ron.

0

pgrep đôi khi tốt hơn ps -ef | grep word vì nó loại trừ grep. Hãy thử

pgrep -f bash 
pgrep -lf bash