Come eseguire un comando dopo uno già in esecuzione, uno esistente termina?


31

Se inizio una sceneggiatura che impiegherà molto tempo, inevitabilmente me ne rendo conto dopo aver iniziato la sceneggiatura e vorrei avere un modo di fare una sorta di avviso una volta terminato.

Quindi, ad esempio, se corro:

really_long_script.sh

e premi invio ... come posso eseguire un altro comando al termine?

Risposte:


44

È possibile separare più comandi da ;, quindi vengono eseguiti in sequenza, ad esempio:

really_long_script.sh ; echo Finished

Se desideri eseguire il programma successivo solo se lo script termina con il codice di ritorno 0 (che di solito significa che è stato eseguito correttamente), allora:

really_long_script.sh && echo OK

Se vuoi il contrario (cioè continua solo se il comando corrente non è riuscito), allora:

really_long_script.sh || echo FAILED

Potresti eseguire il tuo script in background (ma attenzione, gli script di output ( stdoute stderr) continuerebbero ad andare al tuo terminale a meno che non lo reindirizzi da qualche parte), e quindi waitper esso:

really_long_script.sh &
dosomethingelse
wait; echo Finished

Se hai già eseguito uno script, potresti sospenderlo con Ctrl-Z, quindi eseguire qualcosa del tipo:

fg ; echo Finished

Dove fgporta in primo piano il processo sospeso ( bglo farebbe funzionare in background, praticamente come se fosse iniziato &)


@mlissner Amplia la mia risposta per coprire questo caso
aland

8
Poiché fgrestituisce il valore del lavoro che riprende, è possibile utilizzare fg && echo Finishedse si desidera assicurarsi che il comando abbia esito positivo prima di eseguire l'altro comando.
palswim,

12

Puoi anche usare il controllo del lavoro di bash. Se hai iniziato

$ really_long_script.sh

quindi premere ctrl + z per sospenderlo:

^Z
[1]+  Stopped                 really_long_script.sh
$ bg

per riavviare il processo in background (proprio come se fosse stato avviato con really_long_script.sh &). Quindi puoi aspettare questo lavoro in background con

$ wait N && echo "Successfully completed"

dove N è l'ID lavoro (probabilmente 1 se non hai eseguito altri lavori in background) che viene visualizzato anche come [1]sopra.


10

Se il processo non viene eseguito sull'attuale tty, provare questo:

watch -g ps -opid -p <pid>; mycommand

1
Adoro l'uso creativo di watch. Risposta super breve e si impara un nuovo modo utile di usare l'orologio
Piotr Czapla il

2

Si scopre che non è così difficile: puoi semplicemente digitare il comando successivo nella finestra mentre quello esistente è in esecuzione, premere Invio e quando il primo termina, il secondo comando verrà eseguito automaticamente.

Immagino che ci siano modi più eleganti, ma questo sembra funzionare.

Modifica per aggiungere che se si desidera eseguire un avviso al termine del comando, è possibile creare questi alias in .bashrc, quindi eseguirlo alertmentre è in esecuzione:

 alias alert_helper='history|tail -n1|sed -e "s/^\s*[0-9]\+\s*//" -e "s/;\s*alert$//"'
 alias alert='notify-send -i gnome-terminal "Finished Terminal Job" "[$?] $(alert_helper)"'

6
A meno che lo script in esecuzione non preveda l'input in un punto.
Daniel Beck

@Daniel - sì ... questo è un problema. Sparare.
mlissner,

1

Qualche tempo fa ho scritto una sceneggiatura per aspettare la fine di un altro processo. NOISE_CMDpotrebbe essere qualcosa del genere notify-send ..., dato che DISPLAYè impostato correttamente.

#!/bin/bash

NOISE_CMD="/usr/bin/mplayer -really-quiet $HOME/sfx/alarm-clock.mp3"

function usage() {
    echo "Usage: $(basename "$0") [ PROCESS_NAME [ PGREP_ARGS... ] ]"
    echo "Helpful arguments to pgrep are: -f -n -o -x"
}

if [ "$#" -gt 0 ] ; then
    PATTERN="$1"
    shift
    PIDS="$(pgrep "$PATTERN" "$@")"

    if [ -z "$PIDS" ] ; then
        echo "No process matching pattern \"$PATTERN\" found."
        exit
    fi

    echo "Waiting for:"
    pgrep -l "$PATTERN" "$@"

    for PID in $PIDS ; do
        while [ -d "/proc/$PID" ] ; do
            sleep 1
        done
    done
fi

exec $NOISE_CMD

Senza alcun dubbio, fai subito un po 'di rumore. Questo comportamento consente qualcosa di simile per comodità (supponiamo che tu chiami lo script di seguito alarm.sh):

apt-get upgrade ; ~/bin/alarm.sh

Ovviamente puoi fare molte cose divertenti con un tale script, come lasciare un'istanza di alarm.shattesa per un'istanza di alarm.sh, che è in attesa di qualche altro comando. O eseguendo un comando subito dopo che alcune attività di un altro utente connesso hanno terminato ...>: D

Una versione precedente dello script sopra potrebbe essere interessante, se si desidera evitare una dipendenza pgrepe accettare personalmente gli ID del processo di ricerca:

#!/bin/bash

if [ "$#" -lt 2 -o ! -d "/proc/$1" ] ; then
  echo "Usage: $(basename "$0") PID COMMAND [ ARGUMENTS... ]"
  exit
fi

while [ -d "/proc/$1" ] ; do
  sleep 1
done

shift
exec "$@"

Leggermente fuori tema, ma utile in situazioni simili: uno potrebbe essere interessato a reptyr, uno strumento che "ruba" un processo da una shell (padre) e lo esegue dalla shell corrente. Ho provato implementazioni simili ed reptyrè la più bella e affidabile per i miei scopi.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.