Chạy các lệnh bash trong nền mà không cần lệnh in và id xử lý


83

Để chạy một tiến trình ở chế độ nền trong bash khá dễ dàng.

$ 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à dài dòng. Trên dòng đầu tiên được in id công việc và id quy trình của tác vụ nền, sau đó chúng ta có đầu ra của lệnh, cuối cùng chúng ta 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 để chặn đầu ra của việc chạy tác vụ nền để đầu ra trông chính xác như nó sẽ không có dấu và ở cuối không? I E:

$ 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 quy trình nền như một phần của lệnh hoàn thành tab để đầu ra của lệnh đó phải không bị gián đoạn.


Tôi cho rằng 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 bash-
complete

Câu trả lời:


98

Không liên quan đến việc hoàn thành, nhưng bạn có thể nhấn đầu ra đó bằng cách đặt lệnh gọi trong một vỏ con:

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

3
Cảm ơn, điều đó chắc chắn hoạt động. Thật không may, khi chạy một tập lệnh như thế này từ một hàm bash-complete, có vẻ như bash đợi cho đến khi quy trình con hoàn tất trước khi đưa ra kết quả hoàn thành. Điều này thật đáng tiếc vì nó có nghĩa là dường như không thể làm cho nhân viên nền được kích hoạt bằng cách hoàn thành bash.
Alex Spurling

13
Bạn không thể sử dụng điều này nếu bạn muốn waithoàn thành công việc nền.
arekolek,

13

Dựa trên câu trả lời của @ shellter, điều này phù hợp với tôi:

tyler@Tyler-Linux:~$ { echo "Hello I'm a background task" & disown; } 2>/dev/null; sleep .1;
Hello I'm a background task
tyler@Tyler-Linux:~$

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ũ rằng việc tắt ngăn chặn bash xuất ra id quy trình.


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

12

Trong một số phiên bản bash mới hơn và trong ksh93, bạn có thể bao quanh nó bằng một nhóm phụ hoặc nhóm quy trình (tức là { ... }).

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

5
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 tại sao bạn không thấy nó).
Alex Spurling

Tôi đã sao chép chính xác điều này nhưng nó không hoạt động với tôi, nó vẫn hiển thị đầu ra như @AlexSpurling nói. Có lẽ tôi đang làm sai điều gì đó khi những người khác ủng hộ nó, nhưng tôi sợ tôi phải cho nó -1.
Đánh dấu

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

Vì bạn đã nói rõ rằng điều này không hoạt động trong bash nên tôi sẽ xóa -1.
Đánh dấu

1
Đối với tôi, điều này hoạt động tuyệt vời trong một hàm Bash, cũng có thể chờ đợi quá trình wait $!mà dường như không phải là trường hợp cho câu trả lời được chấp nhận.
Jonatan Öström


6

Dựa trên câu trả lời này , tôi đã đưa ra câu trả lời ngắn gọn và chính xác hơn:

silent_background() {
    { 2>&3 "$@"& } 3>&2 2>/dev/null
    disown &>/dev/null  # Prevent whine if job has already completed
}
silent_background date

hoàn hảo! và tái sử dụng cho các công cụ khác
user230910

5

Thử:

user@host:~$ read < <( echo "Hello I'm a background task" & echo $! )
user@host:~$ echo $REPLY
28677

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


1
Đây là hoàn hảo! Cảm ơn bạn
Adham Atta

4

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

Tôi đang gặp sự cố với phương pháp này (biểu mẫu con) và sử dụng 'chờ'. Tuy nhiên, khi tôi đang chạy nó bên trong một hàm, tôi có thể thực hiện đ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ó sự chậm trễ 5 giây trước khi tôi nhận được lời nhắc của mình.


1

Giải pháp vỏ con hoạt động, nhưng tôi cũng muốn có thể đợi các công việc nền (và không có thông báo "Xong" ở cuối). $!từ một vỏ con không thể "chờ được" trong vỏ 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ờ của riêng tôi, 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[*]}

Vừa đủ dễ.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.