2012-01-27 9 views
8

Sử dụng bash Tôi thường muốn lấy tiêu đề của tệp csv lớn và tìm phần còn lại cho một mục nhập cụ thể. Tôi làm như sau.Tại sao lấy stdin từ một tệp khác với việc nhận nó trên một đường ống?

$ (head -1; grep mike) < tmp.csv 
name,age,favourite colour 
mike,38,blue 

Nhưng lấy đầu vào từ con mèo hoặc bất kỳ lệnh nào khác không hoạt động - có vẻ như grep không bao giờ được chuyển phần còn lại của tệp.

$ cat tmp.csv | (head -1; grep mike) 
name,age,favourite colour 

Tại sao có hành vi khác trong hai trường hợp này?

+0

'wc -l test.txt' -output-> 3' (đầu -1>/dev/null; wc -l) 2.! – danihp

+0

Tôi có một số lý thuyết, nhưng tôi không thể tái tạo điều này với bash 3.2.48 (Darwin). Phiên bản bạn đang sử dụng? –

+0

Đây là GNU bash, phiên bản 3.2.25 (1) -release (x86_64-redhat-linux-gnu) trên máy rhel 5.6. – tlrrd

Trả lời

7

Sự khác biệt giữa đọc từ một đường ống và đọc từ một tập tin là bạn có thể lseek vào một tập tin, nhưng không phải trên một ống.

Hành vi ở đây trông (như được thấy qua strace) giống như nó đến từ head, không bị bash. head sẽ đọc bộ đệm và tìm số dòng phù hợp, sau đó lseek ngược về điểm mà dòng đầu cuối cuối cùng kết thúc, để mở xử lý tệp tại địa điểm đó. Như trên, điều này hoạt động nếu nó đọc một tập tin, nhưng không phải nếu nó đọc từ một đường ống.

Tôi không thể nghĩ ra bất kỳ trường hợp nào khác so với những gì bạn đang thực hiện khi hành vi này ở trạng thái head có ý nghĩa, nhưng đúng vậy. Tìm hiểu điều gì đó mới mỗi ngày, tôi nói với bạn ...

+0

+1 Câu trả lời hay, nhưng điều đó thật điên rồ. – cmbuckley

0

Tôi không thể sao chép điều này một cách đáng tin cậy bằng bash 3.2.48. Cả hai đều thành công hoặc cả hai đều thất bại. Nhưng lý do cơ bản cho các lỗi là tệp lớn như thế nào.

cat đọc một bộ đệm (4k-64k tùy thuộc vào hệ thống) và đưa nó xuống ống. head tiêu thụ toàn bộ bộ đệm và sau đó thoát. grep sau đó có quyền truy cập vào tệp sau kích thước bộ đệm. Trên hệ thống của tôi, tôi có thể sử dụng đường ống của bạn chỉ để grep điều hơn một bộ đệm vào tệp (vì vậy tôi có thể grep điều ở cuối tệp dài, nhưng không phải ở đầu sau khi sử dụng head).

Có thể các phiên bản sau của bash tối ưu hóa toán tử < (nhưng không phải cat) để cho phép hoạt động lừa của bạn, nhưng tôi không tin rằng đây là hành vi được hỗ trợ.

+1

Không, nó chắc chắn không phải kích thước. http://sprunge.us/SXCO –

3

Rất lạ. Bạn không nên dựa vào hành vi không có giấy tờ này, sử dụng một cái gì đó giống như thay vì điều này:

sed -n '1p;/mike/p' tmp.csv 
+2

Nó không phải là một hành vi không có giấy tờ. Mọi thứ hoạt động như mong đợi (xem câu trả lời ottos ác). Nó chỉ là một thực hành không tốt - để sử dụng '(command1; command2)' xây dựng để đọc dữ liệu từ đầu vào tiêu chuẩn chung bởi vì cái thứ hai phụ thuộc vào hành vi của cái đầu tiên. Vì vậy, bạn cũng đúng với lệnh của bạn. –