Как сравнить вывод запущенного процесса?

5

Я запускаю тест на gem5 simulator , который сохраняет печать вывода на терминал во время его работы. Я уже сохранил образец пробега того же теста в текстовом файле .

Итак, теперь я хочу сравнить выходной поток, который печатается на консоль, с текстовым файлом предыдущего золотого запуска. Если есть разница с выходом по сравнению с текстовым файлом, симуляция должна быть автоматически завершена.

Для тестирования требуется много времени. Меня интересует только первая ошибка в текущем запуске, поэтому я могу сэкономить время ожидания до завершения выполнения, чтобы сравнить оба выхода.     

задан Insanely curious 28.10.2014 в 08:59
источник

3 ответа

3

Я не мог удержаться от недоумения в поиске правильного способа сравнения вывода запущенных процессов (в терминале) с файлом «золотой прогон», как вы упомянули.

Как поймать вывод текущего процесса

Я использовал команду script с опцией -f . Это записывает текущее (текстовое) содержимое терминала в файл; параметр -f должен обновлять выходной файл в каждом событии записи на терминал. Команда сценария предназначена для записи всех событий, которые происходят в окне терминала.
Скрипт ниже импортирует этот результат периодически.

Что делает этот скрипт

Если вы запустите скрипт в окне терминала, он откроет второе окно терминала, инициированное командой script -f . В этом (втором) окне терминала вы должны запустить свою команду, чтобы запустить тестовый процесс. Хотя этот контрольный процесс дает свои результаты, эти результаты периодически (каждые 2 секунды) по сравнению с вашим «золотым пробегом». Если произошла разница, различный вывод отображается на «основном» (первом) терминале, и сценарий завершается. Появится строка в формате:

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

explanation:

error: (<golden_run_result>, <current_differing_output>)

После этого вывода вы можете безопасно закрыть второе окно, выполнив свои тесты.

Как использовать

  • Скопируйте сценарий ниже в пустой файл.
    Когда вы смотрите на свой файл «золотой ход», первый раздел (до начала фактического теста) не имеет значения и может различаться в разных системах. Поэтому вам нужно определить линию, в которой начинается фактический вывод. В вашем случае я установил его:

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

    измените его, если необходимо.

  • Задайте путь к файлу «золотой прогон».
  • Сохраните сценарий как compare.py , запустите его командой:

    python3 /path/to/compare.py
    

  • открывается второе окно, в котором указано Script started, the file is named </path/to/file>
  • в этом втором окне запустите тестовый тест, первый отличительный результат появится в первом окне:

Какяпротестировал

Ясоздалнебольшуюпрограмму,котораяпоочереднопечатаетстрокиотредактированнойверсиивашегозолотогохода.Ясделалсценарийсравнитьегосоригинальнымфайлом«золотойпрогон».

Сценарий:

#!/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)     
ответ дан Jacob Vlijm 30.10.2014 в 13:33
источник
3

Вы можете использовать diff util.

Предположим, что у вас ваш золотой файл, а другой , который я изменил.

У меня нет вашей программы, поэтому я написал эту симуляцию:

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

Он читает из другого файла (bad_file) и выводит строку за строкой каждую секунду.

Теперь запускаем этот скрипт и перенаправляем его вывод в файл log .

$ simulate > log &

Также я написал скрипт checker:

#!/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

Не забудьте сделать его исполняемым chmod +x checker.sh .

Этот сценарий принимает два аргумента. Первый аргумент - это путь к вашему золотому файлу, второй путь аргумента к вашему файлу журнала.

$ ./checker.sh path_to_golden path_to_log

Эта контрольная сумма подсчитывает количество строк, которые у вас есть прямо сейчас в файле log , и сравнивайте ее с точно таким же количеством строк в golden_file .

Вы запускаете checker каждую секунду и выполняете команду kill при необходимости

Если вы хотите, вы можете написать функцию bash для запуска checker.sh каждую секунду:

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

Часть предыдущего ответа о diff

Вы можете сравнивать их по строкам в виде текстового файла

От man 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

Если мы сравним наши файлы:

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

Мы увидим этот результат:

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

Показывает строку, которая отличается

И вот окончательная команда, я предполагаю, что вы не хотите проверять первые 15 строк:

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

Он покажет вам все различия в двух столбцах. Если вы только хотите знать, есть ли разница, используйте это:

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

Он ничего не печатает, если файлы одинаковые

    
ответ дан c0rp 28.10.2014 в 09:44
0

Я понятия не имею, насколько сложны ваши входные данные, но вы можете использовать что-то вроде awk , чтобы читать каждую строку по мере ее появления и сравнивать ее с известным значением.

$ 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

В этом случае я подаю поток чисел с задержкой по времени и awk работает до тех пор, пока первая переменная на входе (здесь only ) не будет равна 2, а затем выйдет и при этом останавливается поток.

    
ответ дан Oli 28.10.2014 в 09:15