GNU/Linux >> Linux Esercitazione >  >> Linux

Reindirizza stdout mentre un processo è in esecuzione:qual è il processo che invia a /dev/null

Puoi farlo usando strace.

Utilizzando strace puoi spiare cosa viene scritto nel descrittore di file 1, che è il descrittore di file stdout. Ecco un esempio:

strace  -p $pid_of_process_you_want_to_see_stdout_of 2>&1 | \
    sed -re 's%^write\(1,[[:blank:]](.*),[[:blank:]]*[0-9]+\)[[:blank:]]*=[[:blank:]]*[0-9]+%\1%g' 

Potresti voler migliorare il filtro, ma questa sarebbe un'altra domanda. Abbiamo l'output, ma ora dobbiamo riordinarlo.

:ATTENZIONE:questa soluzione presenta alcune limitazioni, vedere i commenti di seguito. Non funzionerà sempre, il tuo chilometraggio potrebbe variare.

Prova:

Metti questo programma (sotto) nel file hello e chmod +x hello

#!/bin/bash

while true
do
    echo -en  "hello\nworld\n"
done

Questo in hello1 e chmod +x hello1

#!/bin/bash
dir=$(dirname $0)
$dir/hello >/dev/null

Questo in hello2 e chmod +x hello2

#!/bin/bash
dir=$(dirname $0)
$dir/hello1 >/dev/null

quindi esegui con ./hello2 >/dev/null , quindi trova il pid del processo hello e digita pid_of_process_you_want_to_see_stdout_of=xyz dove xyz è il pid di ciao, quindi esegui la riga in alto.

Come funziona. Quando viene eseguito hello, bash esegue il fork, reindirizza fd1 a /dev/null , quindi execs hello.Hello invia l'output a fd1 utilizzando la chiamata di sistema write(1, … .Kernel riceve la chiamata di sistema write(1, … , vede che fd 1 è connesso a /dev/null e …

Quindi eseguiamo strace (system-call trace) su hello e vediamo che sta chiamando write(1, "hello\nworld\n") Il resto se la linea sopra sta solo selezionando la linea appropriata della traccia.


No. Dovrai riavviare il comando.

Gli handle Stdio vengono ereditati dal processo padre in figlio. Hai dato al bambino un handle per /dev/nul. È libero di farne quello che vuole, incluse cose come dup()'ing o passarlo ai propri figli. Non esiste un modo semplice per accedere al sistema operativo e modificare ciò a cui puntano gli handle di un altro processo in esecuzione.

Probabilmente, potresti usare un debugger sul bambino e iniziare a zapping del suo stato, sovrascrivendo qualsiasi posizione in cui è memorizzata una copia del valore dell'handle corrente con qualcosa di nuovo, o per tracciare le sue chiamate al kernel, monitorando qualsiasi i/o. Penso che questo stia chiedendo molto alla maggior parte degli utenti, ma può funzionare se si tratta di un singolo processo figlio che non fa nulla di divertente con l'i/o.

Ma anche questo fallisce nel caso generale, ad esempio uno script che crea pipeline e così via, ingannando gli handle e creando molti dei propri figli che vanno e vengono. Questo è il motivo per cui sei praticamente bloccato a ricominciare da capo (e forse reindirizzando a un file che puoi eliminare in seguito anche se non vuoi guardarlo ora.)


Stavo cercando la risposta a questa domanda da molto tempo. Ci sono principalmente due soluzioni disponibili:

  1. Come hai affermato qui, strace option;
  2. Ottenere l'output utilizzando gdb.

Nel mio caso nessuno di loro era soddisfacente, perché prima tronca l'output (e non potrei impostarlo più a lungo). Il secondo è fuori discussione, poiché la mia piattaforma non ha gdb installato:è un dispositivo incorporato.

Raccogliendo alcune informazioni parziali su Internet (non l'ho creato, ho solo messo insieme i pezzi), ho raggiunto la soluzione utilizzando named pipe (FIFO). Quando il processo viene eseguito, il suo output viene indirizzato alla named pipe e se nessuno vuole vederlo, viene applicato un muto listener (tail -f>> /dev/null) per svuotare il buffer. Quando qualcuno vuole ottenere questo output, il processo tail viene ucciso (altrimenti l'output viene alternato tra i lettori) e io cat la pipe. Al termine dell'ascolto, si avvia un'altra coda.

Quindi il mio problema era avviare un processo, uscire dalla shell ssh, quindi accedere nuovamente ed essere in grado di ottenere l'output. Questo è fattibile ora con i seguenti comandi:

#start the process in the first shell
./runner.sh start "<process-name-with-parameters>"&
#exit the shell
exit

#start listening in the other shell
./runner listen "<process-name-params-not-required>"
#
#here comes the output
#
^C

#listening finished. If needed process may be terminated - scripts ensures the clean up
./runner.sh stop "<process-name-params-not-required>"

Lo script che realizza ciò è allegato di seguito. Sono consapevole che non è una soluzione perfetta. Per favore, condividi i tuoi pensieri, forse sarà utile.

#!/bin/sh

## trapping functions
trap_with_arg() {
    func="$1" ; shift
    for sig ; do
        trap "$func $sig" "$sig"
    done
}

proc_pipe_name() {
    local proc=$1;
    local pName=/tmp/kfifo_$(basename ${proc%%\ *});
    echo $pName;
}

listener_cmd="tail -f";
func_start_dummy_pipe_listener() {
    echo "Starting dummy reader";
    $listener_cmd $pipeName >> /dev/null&
}

func_stop_dummy_pipe_listener() {
    tailPid=$(func_get_proc_pids "$listener_cmd $pipeName");
    for pid in $tailPid; do
        echo "Killing proc: $pid";
        kill $tailPid;
    done;
}

func_on_stop() {
        echo "Signal $1 trapped. Stopping command and cleaning up";
    if [ -p "$pipeName" ]; then
        echo "$pipeName existed, deleting it";
        rm $pipeName;
    fi;



    echo "Cleaning done!";
}

func_start_proc() {
    echo "Something here"
    if [ -p $pipeName ]; then
        echo "Pipe $pipeName exists, delete it..";
        rm $pipeName;
    fi;
    mkfifo $pipeName;

    echo "Trapping INT TERM & EXIT";
    #trap exit to do some cleanup
    trap_with_arg func_on_stop INT TERM EXIT

    echo "Starting listener";
    #start pipe reader cleaning the pipe
    func_start_dummy_pipe_listener;

    echo "Process about to be started. Streaming to $pipeName";
    #thanks to this hack, the process doesn't  block on the pipe w/o readers
    exec 5<>$pipeName
    $1 >&5 2>&1
    echo "Process done";
}

func_get_proc_pids() {
    pids="";
    OIFS=$IFS;
    IFS='\n';
    for pidline in $(ps -A -opid -ocomm -oargs | grep "$1" | grep -v grep); do
        pids="$pids ${pidline%%\ *}";
    done;
    IFS=$OIFS;
    echo ${pids};
}

func_stop_proc() {
    tailPid=$(func_get_proc_pids "$this_name start $command");
    if [ "_" == "_$tailPid" ]; then
        echo "No process stopped. The command has to be exactly the same command (parameters may be ommited) as when started.";
    else
        for pid in $tailPid; do
            echo "Killing pid $pid";
            kill $pid;
        done;
    fi;
}

func_stop_listening_to_proc() {
    echo "Stopped listening to the process due to the $1 signal";
    if [ "$1" == "EXIT" ]; then
        if [ -p "$pipeName" ]; then
            echo "*Restarting dummy listener"; 
            func_start_dummy_pipe_listener;
        else 
            echo "*No pipe $pipeName existed";
        fi;
    fi;
}

func_listen_to_proc() {
    #kill `tail -f $pipeName >> /dev/null`
    func_stop_dummy_pipe_listener;

    if [ ! -p $pipeName ]; then 
        echo "Can not listen to $pipeName, exitting...";
        return 1;
    fi;

    #trap the kill signal to start another tail... process
    trap_with_arg func_stop_listening_to_proc INT TERM EXIT
    cat $pipeName;
    #NOTE if there is just an end of the stream in a pipe, we have to do nothing 

}

#trap_with_arg func_trap INT TERM EXIT

print_usage() {
    echo "Usage $this_name [start|listen|stop] \"<command-line>\"";
}

######################################3
############# Main entry #############
######################################

this_name=$0;
option=$1;
command="$2";
pipeName=$(proc_pipe_name "$command");


if [ $# -ne 2 ]; then
    print_usage;
    exit 1;
fi;

case $option in 
start)
    echo "Starting ${command}";
    func_start_proc "$command";
    ;;
listen)
    echo "Listening to ${2}";
    func_listen_to_proc "$command";
    ;;
stop)
    echo "Stopping ${2}";
    func_stop_proc "$command";
    ;;
*)
    print_usage;
    exit 1;
esac;

Linux
  1. In che modo Linux gestisce più separatori di percorsi consecutivi (/home////nomeutente///file)?

  2. Linux:differenza tra /dev/console , /dev/tty e /dev/tty0?

  3. Linux:cosa significa la lettera "u" in /dev/urandom?

  4. Linux:differenza tra /dev/console , /dev/tty e /dev/tty0

  5. echo o print /dev/stdin /dev/stdout /dev/stderr

Che cos'è "/dev/null 2&1" in Linux

Come reindirizzare l'output su /dev/null in Linux

Che cos'è /dev/null in Linux

Quando dovrei usare /dev/shm/ e quando dovrei usare /tmp/?

DD da /dev/zero a /dev/null... cosa succede realmente

Perché sono necessari < o > per usare /dev/tcp