Вызов подпроцесса Python с переменной в цикле for - PullRequest
0 голосов
/ 15 сентября 2018

Я пытаюсь вызвать скрипт bash с помощью подпроцесса, который передается в функцию Popen. Мое намерение состоит в том, чтобы с каждой итерацией новая строка commit из массива out передавалась в качестве аргумента команде Popen. Команда вызывает скрипт bash, который выводит текст, идентифицируемый переменной commit , и извлекает определенные строки из этого конкретного текста. Тем не менее, я не могу получить вывод для очистки в цикле Python for. Прямо сейчас только очищенные данные из окончательного коммита в из передаются в мою окончательную структуру данных (pandas dataframe).

accuracy_dictionary = {}
for commit in out:
    accuracy_dictionary.setdefault(commit, {})
    p2 = subprocess.Popen(['~/Desktop/find_accuracies.sh', commit], encoding='utf-8', shell=True, stdout=subprocess.PIPE)
    outputstring = p2.stdout.read()
    # This part below is less critical to the problem at hand
    # I'm putting the data from each file in a dictionary
    for acc_type_line in outputstring.split('\n'):
        accuracy = acc_type_line.split(': ')
        if accuracy != ['']:
            acc_type = accuracy[0]
            value = accuracy[1]
            accuracy_dictionary[commit][acc_type] = float(value)

acc_data = pd.DataFrame.from_dict(accuracy_dictionary).T

Вот скрипт bash, который вызывается:

"find_accuracies.sh":

#!/bin/sh

COMMIT=$1
git show $COMMIT:blahblahfolder/blahblah.txt | grep --line-buffered 'accuracy'

acc_data возвращает фрейм данных nrows = len ( out ), заполненный уникальными commit s, но значение точно такое же для всех строк для каждого acc_type

Например, мой вывод выглядит так: enter image description here

Как я могу вызвать файл "find_accuracies.sh" с помощью команды подпроцесса и сделать так, чтобы он сбрасывал уникальные значения каждого файла для каждого коммита?

1 Ответ

0 голосов
/ 15 сентября 2018

Я надеюсь, что эта справка поможет решить проблему, с которой вы столкнулись: здесь вы действительно должны использовать communicate с subprocess.PIPE, так как она ожидает завершения команды и выдаст вам весь вывод:

outputstring = p2.communicate()[0]

Вы также можете использовать удобный метод, такой как check_output для того же эффекта:

outputstring = subprocess.check_output(['~/Desktop/find_accuracies.sh', commit],
                                       encoding='utf-8', shell=True)

Или также в py3 использование run должно также сделать:

p2 = subprocess.run(['~/Desktop/find_accuracies.sh', commit],
                    encoding='utf-8', shell=True, stdout=subprocess.PIPE)
outputstring = p2.stdout

Теперь еще несколько комментариев, советов и предложений:

Я немного удивлен, что это работает для вас, поскольку вы используете shell=True и список аргументов должен (см. Абзац, начинающийся с "В POSIX с shell=True" ) make Ваш commit аргумент базового sh обернут вокруг вашего вызова скрипта, а не самого скрипта. В любом случае вы можете (и я бы посоветовал) на самом деле сбросить shell и оставить разрешение HOME на python:

from pathlib import Path
executable = Path.home().joinpath('Desktop/find_accuracies.sh')

p2 = subprocess.run([executable, commit],
                    encoding='utf-8', stdout=subprocess.PIPE)
outputstring = p2.stdout

Вы можете (или должны для py <3.5) также использовать <code>os.path.expanduser('~/Desktop/find_accuracies.sh') вместо Path.home(), чтобы получить скрипт executable. С другой стороны, для> = 3.7 вы можете заменить stdout=subprocess.PIPE на capture_output=True.

И последнее, но не менее важное. Кажется немного ненужным вызывать скрипт bash (особенно в двойном обёртке при вызове sh, как в оригинальном примере) только для запуска от git до grep, когда у нас уже есть скрипт python для обработки информации. На самом деле я попытался бы запустить соответствующую команду git, непосредственно получая большую часть ее вывода, и обработать ее в самом скрипте python, чтобы получить интересующие биты.

...