2011-12-07 38 views
40

Tôi muốn xuất một số dữ liệu vào một đường ống và có quá trình khác thực hiện điều gì đó với dòng dữ liệu theo từng dòng. Dưới đây là ví dụ về đồ chơi:Làm thế nào để tránh tiếng vang đóng FIFO tên ống? - Hành vi hài hước của Unix FIFO

mkfifo pipe 
cat pipe& 
cat >pipe 

Bây giờ tôi có thể nhập bất kỳ thứ gì mình muốn và sau khi nhấn, tôi sẽ thấy ngay một dòng. Nhưng nếu ống thứ hai thay thế với echo:

mkfifo pipe 
cat pipe& 
echo "some data" >pipe 

Các ống đóng sau echocat pipe& kết thúc vì vậy mà tôi không thể vượt qua bất kỳ dữ liệu hơn thông qua các đường ống. Có cách nào để tránh đóng đường ống và quá trình nhận dữ liệu, để tôi có thể truyền nhiều dòng dữ liệu qua đường ống từ tập lệnh bash và xử lý chúng khi chúng đến?

Trả lời

38

Khi FIFO được mở để đọc, nó chặn quá trình gọi (thông thường). Khi một quá trình mở FIFO để viết, thì trình đọc sẽ được bỏ chặn. Khi người viết đóng FIFO, quá trình đọc được EOF (0 byte để đọc), và không có gì hơn nữa có thể được thực hiện ngoại trừ đóng FIFO và mở lại. Do đó, bạn cần sử dụng vòng lặp:

mkfifo pipe 
(while cat pipe; do : Nothing; done &) 
echo "some data" > pipe 
echo "more data" > pipe 

Một cách khác là giữ một số quy trình mở FIFO.

mkfifo pipe 
sleep 10000 > pipe & 
cat pipe & 
echo "some data" > pipe 
echo "more data" > pipe 
+0

Phiên bản thứ hai làm một công việc exellent! Người đầu tiên không làm việc cho tôi vì tôi không muốn khởi động lại quá trình nhận dữ liệu. – user1084871

+9

Bạn có thể lừa và giữ 'con mèo' giữ ống mở để viết bằng cách sử dụng:' cat pipe 3> pipe'. Lệnh 'cat' sẽ không sử dụng bộ mô tả tập tin 3, nhưng sẽ có FIFO được gọi là đường ống mở để viết (mặc dù nó sẽ đọc nó trên một bộ mô tả tập tin khác - có thể là số 4). –

+1

Có 'exec> 6 pipe' không đạt được điều tương tự? Về cơ bản gán 'pipe' cho file-descriptor 6 và giữ nó mở để viết. Thay vì viết thành 'pipe' trực tiếp, bạn có thể muốn ghi vào bộ mô tả đó bằng cách sử dụng'> & 6' nhưng nếu không nó sẽ giữ nó mở iirc – Haravikk

46

Đặt tất cả những điều khoản mà bạn muốn đầu ra cho fifo trong cùng một subshell:

# Create pipe and start reader. 
mkfifo pipe 
cat pipe & 
# Write to pipe. 
(
    echo one 
    echo two 
) >pipe 

Nếu bạn có một số phức tạp hơn, bạn có thể mở các đường ống để viết:

# Create pipe and start reader. 
mkfifo pipe 
cat pipe & 
# Open pipe for writing. 
exec 3>pipe 
echo one >&3 
echo two >&3 
# Close pipe. 
exec 3>&- 
+1

Câu trả lời xuất sắc và thực sự thành công trong việc giữ cho đường ống mở qua một chuỗi lệnh tùy ý phức tạp. – voetsjoeba

+5

Bạn có thể giải thích ngắn gọn về cách thức hoạt động của nó không? Đặc biệt là dòng cuối cùng: 'exec 3> & -' –

+2

@NickChammas: trong ví dụ thứ hai, 'exec 3> pipe' mở tập tin mô tả 3 để ghi vào' pipe'; hai lệnh 'echo' ghi vào đường ống nhờ sự chuyển hướng đầu ra; 'exec 3> & -' cuối cùng là cách bạn đóng một bộ mô tả tập tin mở - bộ mô tả 3 trong trường hợp này. Tại thời điểm đó, 'con mèo' chạy trong nền lấy một EOF và kết thúc. –

1

Để thay thế cho các giải pháp khác ở đây, bạn có thể gọi cat trong vòng lặp làm đầu vào cho lệnh của mình:

mkfifo pipe 
(while true ; do cat pipe ; done) | bash 

Bây giờ bạn có thể ăn nó lệnh cùng một lúc và nó sẽ không đóng cửa:

echo "'echo hi'" > pipe 
echo "'echo bye'" > pipe 

Bạn sẽ phải giết quá trình khi bạn muốn nó biến mất, dĩ nhiên rồi. Tôi nghĩ đây là giải pháp thuận tiện nhất vì nó cho phép bạn chỉ định hành vi không thoát khi bạn tạo quy trình.

1

tôi tăng cường phiên bản thứ hai từ câu trả lời của Jonathan Leffler để hỗ trợ đóng ống:

dir=`mktemp -d /tmp/temp.XXX` 
keep_pipe_open=$dir/keep_pipe_open 
pipe=$dir/pipe 

mkfifo $pipe 
touch $keep_pipe_open 

# Read from pipe: 
cat < $pipe & 

# Keep the pipe open: 
while [ -f $keep_pipe_open ]; do sleep 1; done > $pipe & 

# Write to pipe: 
for i in {1..10}; do 
    echo $i > $pipe 
done 

# close the pipe: 
rm $keep_pipe_open 
wait 

rm -rf $dir 
14

Bạn có thể giải quyết việc này rất dễ dàng bằng cách mở phía đọc của ống trong chế độ đọc-ghi. Người đọc chỉ nhận được EOF khi người viết cuối cùng đóng. Vì vậy, mở nó trong đọc-ghi đảm bảo rằng luôn luôn có ít nhất một nhà văn.

Vì vậy, thay đổi ví dụ thứ hai của bạn để:

mkfifo pipe 
cat <>pipe & 
echo "some data" >pipe 
+1

Đây rõ ràng là câu trả lời đúng. Cảm ơn. –

+1

Với phương pháp này tôi không thể làm việc ra làm thế nào để đóng ống, tôi chỉ có thể giết chết quá trình mèo mà có thể không hành xử theo cùng một cách. Ví dụ, nếu con mèo thực sự là một chương trình awk với một khối END, khối END sẽ không được thực hiện khi nó nhận được một SIGTERM. – pix

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