2011-10-07 24 views
43

Để chạy một quá trình trong nền trong bash là khá dễ dàng.Chạy lệnh bash ở chế độ nền mà không cần in mã số công việc và quá trình

$ echo "Hello I'm a background task" & 
[1] 2076 
Hello I'm a background task 
[1]+ Done     echo "Hello I'm a background task" 

Tuy nhiên, đầu ra là tiết. Trên dòng đầu tiên được in id công việc và id quá trình của tác vụ nền, sau đó chúng tôi có đầu ra của lệnh, cuối cùng chúng tôi có id công việc, trạng thái của nó và lệnh đã kích hoạt công việc.

Có cách nào để ngăn chặn đầu ra của chạy tác vụ nền sao cho đầu ra trông chính xác như nó sẽ không có dấu và ở cuối? Tức là:

$ echo "Hello I'm a background task" & 
Hello I'm a background task 

Lý do tôi hỏi là tôi muốn chạy một tiến trình nền như một phần của một lệnh bằng tab completion để đầu ra của lệnh đó phải được không bị gián đoạn để thực hiện bất kỳ ý nghĩa.

+0

Tôi giả sử bạn nên thêm 2>/dev/null vào bất kỳ thứ gì bạn làm bên trong các tập lệnh hoàn thành bash – sehe

Trả lời

48

Không liên quan đến hoàn thành, nhưng bạn có thể đàn áp đầu ra bằng cách đặt các cuộc gọi trong một subshell:

(echo "Hello I'm a background task" &) 
+2

Cảm ơn, điều đó chắc chắn hoạt động. Thật không may, khi chạy một kịch bản như thế này từ một hàm bash-hoàn thành, nó xuất hiện bash đợi cho đến khi tiến trình con hoàn tất trước khi đưa ra kết quả hoàn thành. Điều này là không may vì nó có nghĩa là nó không xuất hiện để có thể làm cho nền công nhân được kích hoạt bởi bash-hoàn thành. –

+3

Bạn không thể sử dụng điều này nếu bạn muốn 'chờ đợi 'cho công việc nền để kết thúc. – arekolek

10

Bạn sẽ phải bao quanh nó với nhóm phụ hoặc nhóm xử lý (ví dụ: { ... }).

/home/shellter $ { echo "Hello I'm a background task" & } 2>/dev/null 
Hello I'm a background task 
/home/shellter $ 

IHTH

chỉnh sửa

theo hướng dẫn trong downvote @ Mark 's, tôi đã nghiên cứu rằng điều này không hoạt động chính xác trong bash. Tính năng này hoạt động như được hiển thị bên dưới ksh93.

Bận ngay bây giờ, nhưng tôi sẽ cập nhật câu trả lời này với những gì tôi đã đưa vào nhận xét cho câu trả lời này và @Tizord, nhưng tôi không thấy câu trả lời dễ dàng về cách chuyển hướng std-err từ nền bài tập. (Đây có thể là có thể với exec thao tác)

+1

Khi tôi sử dụng dấu ngoặc nhọn, dòng đầu ra cuối cùng vẫn hiển thị (Tôi không chắc chắn tại sao bạn không thấy nó). –

+0

Tôi đã sao chép chính xác nhưng nó không hoạt động đối với tôi, nó vẫn hiển thị đầu ra như @AlexSpurling nói. Có lẽ tôi đang làm điều gì đó sai vì những người khác đã bình chọn nó, nhưng tôi e rằng tôi phải đưa nó -1. – Mark

+0

@Mark: Tôi đã thực hiện một số kiểm tra nhanh với điều này và tôi thấy vấn đề là tôi tiếp tục sử dụng 'ksh93 +' làm lớp vỏ primariy của mình. Mã này hoạt động như đã hứa trong ksh. nhưng như OP được gắn thẻ với 'bash' tôi hiểu dv của bạn. Xem kết quả thử nghiệm bash trên câu trả lời của @ Tyzoid. Chúc mọi người may mắn! – shellter

9

Building tắt của câu trả lời @ Shellter, điều này đã làm việc cho tôi:

[email protected]:~$ { echo "Hello I'm a background task" & disown; } 2>/dev/null; sleep .1; 
Hello I'm a background task 
[email protected]:~$ 

Tôi không biết lý do đằng sau điều này, nhưng tôi nhớ từ một bài đăng cũ đã không cho phép bash xuất ra các id quá trình.

+0

Nó hoạt động, nhưng nó nuốt tất cả stderr. – Mark

+0

@Tyzoid. Tôi đã thử giải pháp của bạn trong một bash shell (v 4.2.37) và có kết quả thú vị. 1. Tôi có cùng một kết quả chỉ cần thêm ';' ở cuối. (không ngủ). 2. NHƯNG nhận thấy rằng khi tôi thêm 'echo STDERR 2> & 1' vào dòng" next ", thì điều' [1] + Done ... 'xuất hiện! . 3. Giải pháp của tôi (như tôi đã lưu ý) hoạt động trong 'ksh' và' echo STDERR 2> & 1' chỉ tạo ra đầu ra STDERR. Vâng, sống và học hỏi cho cả hai chúng tôi. Chúc mọi người may mắn. – shellter

5

Dựa trên câu trả lời ở trên, nếu bạn cần phải cho phép stderr để đi qua từ lệnh:

f() { echo "Hello I'm a background task" >&2; } 
{ f 2>&3 &} 3>&2 2>/dev/null 
3

Hãy thử:

[email protected]:~$ read < <(echo "Hello I'm a background task" & echo $!) 
[email protected]:~$ echo $REPLY 
28677 

Và Cha đã giấu cả đầu raPID. Lưu ý rằng bạn vẫn có thể truy xuất PID từ $ REPLY

+0

Điều này thật hoàn hảo! Cảm ơn bạn –

3

Xin lỗi vì phản hồi cho bài đăng cũ, nhưng tôi thấy điều này hữu ích cho người khác và đó là phản hồi đầu tiên trên Google.

Tôi gặp sự cố với phương thức này (các vỏ con) và sử dụng 'chờ'.Tuy nhiên, như tôi đã chạy nó bên trong một hàm, tôi đã có thể làm điều này:

function a { 
    echo "I'm background task $1" 
    sleep 5 
} 

function b { 
    for i in {1..10}; do 
     a $i & 
    done 
    wait 
} 2>/dev/null 

Và khi tôi chạy nó:

$ b 
I'm background task 1 
I'm background task 3 
I'm background task 2 
I'm background task 4 
I'm background task 6 
I'm background task 7 
I'm background task 5 
I'm background task 9 
I'm background task 8 
I'm background task 10 

Và có một sự chậm trễ 5 giây trước khi tôi nhận được dấu nhắc của tôi trở lại.

1

Giải pháp vỏ máy hoạt động, nhưng tôi cũng muốn có thể chờ công việc nền (và không có thông báo "Xong" ở cuối). $! từ một subshell không phải là "waitable" trong shell tương tác hiện tại. Giải pháp duy nhất phù hợp với tôi là sử dụng chức năng chờ riêng của mình, rất đơn giản:

myWait() { 
    while true; do 
    sleep 1; STOP=1 
    for p in $*; do 
     ps -p $p >/dev/null && STOP=0 && break 
    done 
    ((STOP==1)) && return 0 
    done 
} 

i=0 
((i++)); p[$i]=$(do_whatever1 & echo $!) 
((i++)); p[$i]=$(do_whatever2 & echo $!) 
.. 
myWait ${p[*]} 

Đủ dễ dàng.

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