¿Cómo comparar el resultado de un proceso en ejecución?

¿Cómo comparar el resultado de un proceso en ejecución?

Estoy ejecutando un punto de referencia ensimulador gem5, que sigue imprimiendo la salida al terminal mientras se ejecuta. Ya almacené una ejecución de muestra del mismo punto de referencia en unArchivo de texto.

Ahora quiero comparar el flujo de salida que se imprime en la consola con el archivo de texto de la ejecución dorada anterior. Si hay una diferencia con la salida en comparación con el archivo de texto, la simulación debe finalizar automáticamente.

El punto de referencia requiere mucho tiempo para ejecutarse. Solo me interesa el primer error en la ejecución actual, para poder ahorrar tiempo de espera hasta que se complete la ejecución para comparar ambas salidas.

Respuesta1

No pude resistirme a pensar un poco más en cómo encontrar una forma adecuada de comparar la salida de unproceso en ejecución(en la terminal) contra un archivo de "ejecución dorada", como lo mencionas.

Cómo capturar el resultado del proceso en ejecución

Usé el scriptcomando con la -fopción. Esto escribe el contenido actual (textual) del terminal en un archivo; la -fopción es actualizar el archivo de salida en cada evento de escritura en el terminal. El comando de secuencia de comandos está diseñado para mantener un registro de todo lo que sucede en una ventana de terminal.
El siguiente script importa esta salida periódicamente.

Qué hace este script

Si ejecuta el script en una ventana de terminal, abre una segunda ventana de terminal, iniciada con el script -fcomando. En esta (segunda) ventana de terminal, debe ejecutar su comando para iniciar el proceso de evaluación comparativa. Si bien este proceso de referencia produce sus resultados, estos resultados se comparan periódicamente (cada 2 segundos) con su "ejecución dorada". Si se produjo una diferencia, la salida diferente se muestra en la terminal "principal" (primera) y el script finaliza. Aparece una línea, en el formato:

error: ('Solutions: 13.811084', 'Solutions: 13.811084 aap noot mies')

explanation:

error: (<golden_run_result>, <current_differing_output>)

Después de este resultado, puede cerrar de forma segura la segunda ventana y ejecutar sus pruebas.

Cómo utilizar

  • Copie el siguiente script en un archivo vacío.
    Cuando observa su archivo de "ejecución dorada", la primera sección (antes de que comience la prueba real) es irrelevante y puede diferir en diferentes sistemas. Por lo tanto, es necesario definir la línea donde comienza la salida real. En tu caso lo puse en:

    first_line = "**** REAL SIMULATION ****"
    

    cámbielo si es necesario.

  • Establezca la ruta a su archivo "golden run".
  • Guarde el script como compare.py, ejecútelo con el comando:

    python3 /path/to/compare.py
    

    `

  • se abre una segunda ventana que diceScript started, the file is named </path/to/file>
  • En esta segunda ventana, ejecute su prueba comparativa, el primer resultado diferente aparece en la primera ventana:

ingrese la descripción de la imagen aquí

como lo probé

Creé un pequeño programa que imprime las líneas de una versión editada de tu ejecución dorada, una por una. Hice que el script lo comparara con el archivo original de "ejecución dorada".

La secuencia de comandos:

#!/usr/bin/env python3

import subprocess
import os
import time

home = os.environ["HOME"]

# files / first_line; edit if necessaary
golden_run = "/home/jacob/Bureaublad/log_example"
first_line = "**** REAL SIMULATION ****"

# don't change anything below
typescript_outputfile = home+"/"+"scriptlog.txt"
# commands
startup_command = "gnome-terminal -x script -f "+typescript_outputfile
clean_textcommand = "col -bp <"+typescript_outputfile+" | less -R"
# remove old outputfile
try:
    os.remove(typescript_outputfile)
except Exception:
    pass
# initiate typescript
subprocess.Popen(["/bin/bash", "-c", startup_command])
time.sleep(1)
# read golden run
with open(golden_run) as src:
    original = src.read()
orig_section = original[original.find(first_line):]
# read last output of current results so far
def get_last():
    read = subprocess.check_output(["/bin/bash", "-c", clean_textcommand]).decode("utf-8")
    if not first_line+"\n" in read:
        return "Waiting for first line"
    else:
        return read[read.find(first_line):]
    with open(typescript_outputfile, "wt") as clear:
        clear.write("\n")
# loop
while True:
    current = get_last()
    if current == "\n":
        pass
    else:
        if not current in orig_section and current != "Waiting for first line":
            orig = orig_section.split("\n")
            breakpoint = current.split("\n")
            diff = [(orig[i], breakpoint[i]) for i in range(len(breakpoint)) \
                    if not orig[i] == breakpoint[i]]
            print("error: "+str(diff[0]))
            break
        else:
            pass
    time.sleep(5)

Respuesta2

Puedes usar diffutil.

Supongamos que tienessulima dorada, yotroque cambié.

No tengo tu programa ejecutándose, así que escribí esta simulación:

#!/bin/bash
    while read -r line; do
        echo "$line";
        sleep 1;
    done < bad_file

se lee desdeotrofile (bad_file) y genera línea por línea cada segundo.

Ahora ejecute este script y redirija su salida al logarchivo.

$ simulate > log &

También escribí un script de verificación:

#!/bin/bash

helper(){
    echo "This script takes two file pathes as arguments."
    echo "$0 path/to/file1 path/to/file2"
}

validate_input(){
    if [[ $# != 2 ]]; then 
        helper
        exit 1
    fi

    if [[ ! -f "$1" ]]; then
        echo "$1" file is not exist.
        helper
        exit 1
    fi
    if [[ ! -f "$2" ]]; then
        echo "$2" file is not exist.
        helper
        exit 1
    fi
}

diff_files(){
# As input takes two file and check
# difference between files. Only checks
# number of lines you have right now in
# your $2 file, and compare it with exactly
# the same number of lines in $1
    diff -q -a -w <(tail -n+"$ULINES" $1 | head -n "$CURR_LINE") <(tail -n+"$ULINES" $2 | head -n "$CURR_LINE")
}

get_curr_lines(){
# count of lines currenly have minus ULINES
    echo "$[$(cat $1 | wc -l) - $ULINES]"
}

print_diff_lines(){
    diff -a -w --unchanged-line-format="" --new-line-format=":%dn: %L" "$1" "$2" | grep -o ":[0-9]*:" | tr -d ":"
}

ULINES=15 # count of first unused lines. How many first lines to ignore

validate_input "$1" "$2"
CURR_LINE=$(get_curr_lines "$2") # count of lines currenly have minus ULINES

if [[ $CURR_LINE < 0 ]];then
    exit 0
fi

IS_DIFF=$(diff_files "$1" "$2")
if [[ -z "$IS_DIFF" ]];then
    echo "Do nothing if they are the same"
else
    echo "Do something if files already different"
    echo "Line number: " `print_diff_lines "$1" "$2"`
fi

No olvides hacerlo ejecutable chmod +x checker.sh.

Este script requiere dos argumentos. El primer argumento es la ruta a su archivo dorado, el segundo argumento es la ruta a su archivo de registro.

$ ./checker.sh path_to_golden path_to_log

Este verificador cuenta el número de líneas que tiene ahora en su logarchivo y lo compara con exactamente el mismo número de líneas en golden_file.

Ejecuta el verificador cada segundo y ejecuta el comando matar si es necesario

Si lo desea, puede escribir la función bash para que se ejecute checker.shcada segundo:

$ chk_every() { while true; do ./checker.sh $1 $2; sleep 1; done; }

Parte de la respuesta anterior sobre diff.

Puedes compararlos línea por línea como un archivo de texto.

Deman diff

NAME
   diff - compare files line by line

   -a, --text
          treat all files as text

   -q, --brief
          report only when files differ

   -y, --side-by-side
          output in two columns

Si comparamos nuestros archivos:

$ diff -a <(tail -n+15 file1) <(tail -n+15 file2)

Veremos esta salida:

2905c2905
< Solutions: 0.686669
---
> Solutions: 0.686670
2959c2959
< Solutions: 0.279124
---
> Solutions: 0.279125
3030c3030
< Solutions: 0.539016
---
> Solutions: 0.539017
3068c3068
< Solutions: 0.308278
---
> Solutions: 0.308279

Muestra la línea que difiere.

Y aquí está el comando final, asumiendo que no deseas verificar las primeras 15 líneas:

$ diff -y -a <(tail -n+15 file1) <(tail -n+15 file2)

Le mostrará todas las diferencias en dos columnas. Si sólo quieres saber si hay alguna diferencia, usa esto:

$ diff -q -a <(tail -n+15 file1) <(tail -n+15 file2)

No imprimirá nada si los archivos son iguales.

Respuesta3

No tengo idea de cuán complicados son tus datos de entrada, pero podrías usar algo como awkleer cada línea a medida que ingresa y compararla con un valor conocido.

$ for i in 1 2 3 4 5; do echo $i; sleep 1; done | \
  awk '{print "Out:", $0; fflush(); if ($1==2) exit(0)}'
Out: 1
Out: 2

En este caso, estoy ingresando un flujo de números con retardo de tiempo y awklo estoy ejecutando hasta que la primera variable en la entrada (lasolovariable aquí) es igual a 2, luego sale y al hacerlo detiene la corriente.

información relacionada