Dalam skrip shell, bagaimana saya bisa (1) memulai perintah di latar belakang (2) menunggu x detik (3) menjalankan perintah kedua saat perintah itu sedang berjalan?

11

Inilah yang saya butuhkan untuk terjadi:

  1. mulai proses A di latar belakang
  2. tunggu x detik
  3. mulai proses B di latar depan

Bagaimana saya bisa membuat penantian terjadi?

Saya melihat bahwa 'tidur' sepertinya menghentikan segalanya dan saya tidak benar-benar ingin 'menunggu' proses A selesai sepenuhnya. Saya telah melihat beberapa loop berdasarkan waktu tetapi saya bertanya-tanya apakah ada sesuatu yang lebih bersih.

Julie
sumber
4
Saya menyarankan agar Anda meningkatkan pertanyaan ini dengan memberikan contoh sederhana tentang apa yang sudah Anda coba.
Andy Dalton
10
Di mana Anda mendapatkan kesan yang sleepmenghentikan proses-A? Bisakah Anda menunjukkan proses pengujian yang Anda gunakan, atau menampilkan indikasi ini? Jika proses-A adalah tersendat-sendat, itu lebih mungkin bahwa itu mencoba membaca dari terminal sementara berjalan di latar belakang dan mendapatkan dihentikan karena alasan itu, bukan sesuatu yang berhubungan dengan sleep.
Charles Duffy
3
... jika itu adalah kasus, process_a </dev/null &akan melampirkan stdin untuk /dev/nulldaripada TTY, dan yang mungkin cukup untuk menghindari masalah tersebut.
Charles Duffy
Dari pengalaman saya, tidur hanya akan memblokir proses saat ini dan dengan demikian bukan proses yang sebelumnya dimulai di latar belakang dengan &
MADforFUNandHappy

Jawaban:

28

Kecuali jika saya salah memahami pertanyaan Anda, itu bisa dicapai dengan skrip pendek ini:

#!/bin/bash

process_a &
sleep x
process_b

(dan tambahkan tambahan waitdi bagian akhir jika Anda ingin skrip Anda menunggu process_ahingga selesai sebelum keluar).

Anda bahkan dapat melakukan ini sebagai satu-liner, tanpa perlu skrip (seperti yang disarankan oleh @BaardKopperud):

process_a & sleep x ; process_b
dr_
sumber
6
Perhatikan bahwa Anda tidak perlu bashuntuk itu, shell apa pun akan termasuk sistem Anda sh, jadi Anda tidak perlu menambahkan ketergantungan pada bash untuk skrip Anda.
Stéphane Chazelas
4
Atau cukup: process_a & sleep x; process_b
Baard Kopperud
9

Anda dapat menggunakan operator kontrol latar belakang (&) untuk menjalankan proses di latar belakang dan sleepperintah untuk menunggu sebelum menjalankan proses kedua, yaitu:

#!/usr/bin/env bash
# script.sh

command1 &
sleep x
command2

Berikut adalah contoh dari dua perintah yang mencetak beberapa pesan bertanda waktu:

#!/usr/bin/env bash

# Execute a process in the background
echo "$(date) - Running first process in the background..."
for i in {1..1000}; do
    echo "$(date) - I am running in the background";
    sleep 1;
done &> background-process-output.txt &

# Wait for 5 seconds
echo "$(date) - Sleeping..."
sleep 5 

# Execute a second process in the foreground
echo "$(date) - Running second process in the foreground..."
for i in {1..1000}; do
    echo "$(date) - I am running in the foreground";
    sleep 1;
done

Jalankan untuk memverifikasi bahwa ia menunjukkan perilaku yang diinginkan:

user@host:~$ bash script.sh

Fri Dec  1 13:41:10 CST 2017 - Running first process in the background...
Fri Dec  1 13:41:10 CST 2017 - Sleeping...
Fri Dec  1 13:41:15 CST 2017 - Running second process in the foreground...
Fri Dec  1 13:41:15 CST 2017 - I am running in the foreground
Fri Dec  1 13:41:16 CST 2017 - I am running in the foreground
Fri Dec  1 13:41:17 CST 2017 - I am running in the foreground
Fri Dec  1 13:41:18 CST 2017 - I am running in the foreground
Fri Dec  1 13:41:19 CST 2017 - I am running in the foreground
Fri Dec  1 13:41:20 CST 2017 - I am running in the foreground
...
...
...
igal
sumber
2
Pertanyaannya adalah untuk "memulai proses B di latar depan ".
Sparhawk
1
@Sparhawk Wow. Benar-benar salah baca itu - tidak ada penjelasan. Terima kasih atas head-up - kode diperbaiki. Nostalgia serius dari nama pengguna Anda, btw.
igal
1
Jangan khawatir! (Juga nama pengguna pada awalnya adalah referensi untuk bab ini , tetapi saya kemudian baru menyadari bahwa itu adalah karakter Eddings! Dan membuat saya ingin membaca kembali buku-buku itu ...)
Sparhawk
5

Saya suka jawaban @ dr01 tetapi dia tidak memeriksa kode keluar dan jadi Anda tidak tahu apakah Anda berhasil atau tidak.

Inilah solusi yang memeriksa kode keluar.

#!/bin/bash

# run processes
process_a &
PID1=$!
sleep x
process_b &
PID2=$!
exitcode=0

# check the exitcode for process A
wait $PID1    
if (($? != 0)); then
    echo "ERROR: process_a exited with non-zero exitcode" >&2
    exitcode=$((exitcode+1))
fi

# check the exitcode for process B
wait $PID2
if (($? != 0)); then
    echo "ERROR: process_b exited with non-zero exitcode" >&2
    exitcode=$((exitcode+1))
fi
exit ${exitcode}

biasanya saya menyimpan PID dalam array bash dan kemudian memeriksa pid adalah untuk loop.

Trevor Boyd Smith
sumber
2
Anda mungkin ingin mencerminkan kode keluar tersebut dalam status keluar dari skrip Anda sepertiA & sleep x; B; ret=$?; wait "$!" || exit "$ret"
Stéphane Chazelas
1
@ StéphaneChazelas ide bagus. saya memperbarui kode untuk memastikan kode keluar yang tidak nol dikembalikan jika salah satu atau keduanya gagal.
Trevor Boyd Smith
OP ingin process_bberjalan di latar depan. Agaknya process_abisa keluar saat process_bsedang berjalan, tetapi Anda masih bisa waituntuk itu dan mendapatkan status keluar setelah Anda mengumpulkan status keluar dari latar depan process_bdengan cara biasa, dengan $?langsung.
Peter Cordes