tạm dừng một tập lệnh bash cho đến khi các lệnh trước kết thúc


20

Tôi có một tập lệnh bash trông giống như sau:

##script
#!/bin/bash
rm data*
rm logfile*
for i in {1..30}
do
## append a & if you want to run it parallel;
nohup Rscript --vanilla main.R 10 100 $i &> logfile"$i" &
done

Tôi muốn tạo một vòng lặp khác sau vòng đầu tiên để tiếp tục cho 30. Ví dụ:

##script
#!/bin/bash
rm data*
rm logfile*
for i in {1..30}
do
## append a & if you want to run it parallel;
nohup Rscript --vanilla main.R 10 100 $i &> logfile"$i" &

for i in {31..60}
do
## append a & if you want to run it parallel;
nohup Rscript --vanilla main.R 10 100 $i &> logfile"$i" &
done

Tôi muốn bộ công việc đầu tiên kết thúc trước khi bắt đầu bộ công việc mới. Nhưng vì nohupcó vẻ như tất cả chúng đều chạy cùng một lúc.

Tôi có nohupbởi vì tôi đăng nhập từ xa vào máy chủ của mình và bắt đầu các công việc ở đó và sau đó đóng bash của tôi. Có một giải pháp thay thế?


1
Tìm kiếm hướng dẫn cho waitnội dung.
Satō Katsura

Câu trả lời:


22

Bạn sẽ muốn sử dụng waitlệnh để làm điều này cho bạn. Bạn có thể nắm bắt tất cả các ID xử lý con và chờ chúng một cách cụ thể hoặc nếu chúng là các tiến trình nền duy nhất mà tập lệnh của bạn đang tạo, bạn chỉ có thể gọi waitmà không cần đối số. Ví dụ:

#!/bin/bash
# run two processes in the background and wait for them to finish

nohup sleep 3 &
nohup sleep 10 &

echo "This will wait until both are done"
date
wait
date
echo "Done"

6

Một vài điểm:

  • Nếu mục tiêu của bạn nohuplà ngăn chặn một lối thoát shell từ xa giết chết các tiến trình worker của bạn, bạn nên sử dụng nohuptrên chính script, chứ không phải trên các process worker riêng lẻ mà nó tạo ra.

  • Như đã giải thích ở đây , nohupchỉ ngăn các quá trình nhận SIGHUP và tương tác với thiết bị đầu cuối, nhưng nó không phá vỡ mối quan hệ giữa hệ vỏ và các tiến trình con của nó.

  • Do điểm trên, có hoặc không có nohup, một đơn giản waitgiữa hai forvòng sẽ khiến lần thứ hai forchỉ được thực hiện sau khi tất cả các tiến trình con được bắt đầu bởi lần đầu tiên forđã thoát.

  • Với một cách đơn giản wait:

    tất cả các tiến trình con hiện đang hoạt động được chờ đợi và trạng thái trả về bằng không.

  • Nếu bạn chỉ cần chạy lần thứ hai fornếu không có lỗi nào trong lần đầu tiên, thì bạn sẽ cần lưu từng công nhân PID với $!và chuyển tất cả chúng sang wait:

    pids=
    for ...
        worker ... &
        pids+=" $!"
    done
    wait $pids || { echo "there were errors" >&2; exit 1; }

Có thể có các công việc khác đang chạy trên máy chủ. Vì vậy, tôi chỉ muốn đợi lô của mình .. chúng là các tập lệnh R để chúng được chạy theo Rhoặc cc1plustrong toplệnh
masfenix

Ngoài ra tôi muốn sử dụng nohup bên trong để chạy tất cả các lệnh trong "song song". về cơ bản đây là những mô phỏng cho một chương trình khoa học. Tôi muốn chạy tổng cộng 180 mô phỏng, nhưng theo đợt 60. Bộ đếm cũng cần phải đi từ 1 đến 180. Nếu tôi thực hiện chúng một lần, sẽ mất quá nhiều thời gian.
masfenix

waitnguyên nhân bashđể chờ các công việc nền nó tự sinh ra, không có gì khác. Có thể có một số nhầm lẫn ở đây - các forvòng lặp này , bạn đã lưu chúng vào một tệp và gọi chúng như một tập lệnh (những gì tôi giả sử, vì ##scriptdòng), hoặc bạn đang gõ chúng bằng tay trong thiết bị đầu cuối?
Matei David

-1

Sử dụng fgnội dung. Nó chờ cho đến khi quá trình nền kết thúc.

Hãy thử help fgđể biết chi tiết.


Một kịch bản chạy mà không có kiểm soát công việc.
Kusalananda

-1

Nếu bạn chèn một cái gì đó như đoạn mã sau vào giữa hai forvòng của bạn , nó có thể giúp ích.

flag=0

while [ flag -eq 0 ]
do
  ps -ef | grep "Rscript --vanilla" | grep -v grep > /dev/null
  flag=${?}
  sleep 10
done

Tất nhiên, nếu ứng dụng của bạn Rscriptcó cơ hội không hoàn thành thành công và tồn tại xung quanh, vòng lặp thứ hai của bạn có thể không có cơ hội để chạy. Đoạn mã ở trên giả định, tất cả các quy trình với mã định danh Rscript --vanillasẽ hoàn thành và biến mất đúng cách. Không biết ứng dụng của bạn làm gì và nó chạy như thế nào, tôi phải dựa vào giả định này.

CHỈNH SỬA

Trong ánh sáng của các ý kiến, điều này sẽ phù hợp hơn với nhu cầu của bạn. (nó bao gồm mã gốc của bạn cũng như logic kiểm tra hoàn thành)

for i in {1..30}
do
## append a & if you want to run it parallel;
nohup Rscript --vanilla main.R 10 100 $i &> logfile"$i" &
pids[$i]=${!}
done

flag=0

while [ flag -eq 0 ] 
do
  for PID in $(echo ${pids[@]})
  do
    flag=1
    ps -ef | grep ${PID} | grep -v grep >/dev/null; r=${?}
    if [ ${r} -eq 0 ]
    then 
      flag=0
    fi
  done
done

for i in {31..60}
do
## append a & if you want to run it parallel;
nohup Rscript --vanilla main.R 10 100 $i &> logfile"$i" &
done

Tên quy trình trong tophiển thị Rđôi khi hoặc cc1plus.
masfenix

Trong trường hợp đó, bạn sẽ cần tìm mẫu số chung, hiển thị trong ps -efdanh sách. Hoặc sau mỗi nohuplệnh, ghi lại PID vào một biến (tốt nhất là một mảng) bằng cách echo ${!}và kiểm tra nhóm PID này. Khi tất cả biến mất, bạn có thể tiến hành forvòng lặp thứ hai
MelBurslan
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.