subprocess
- хитрый инструмент. Первое, что нужно знать, это то, что каждый вызов subprocess.run()
будет вызывать один новый процесс. Все остальное будет рассматриваться как аргументы этого нового процесса (argv
в C). Запуск кода, который вы разместили, будет переводить на это:
cd /Applications/MATLAB_R2018b.app/bin [lots of other stuff...]
Поскольку cd
выполнит свою задачу, используя первый аргумент и игнорируя любые дополнительные аргументы, он успешно завершается и возвращает.
Вот тест, который демонстрирует это более наглядно:
>>> cmds=['cd .. ls who what where when why']
>>> sp.run(cmds, shell=True)
CompletedProcess(args=['cd .. ls who what where when why'], returncode=0)
Если мы добавим ;pwd
к концу cmds[0]
, он покажет один уровень выше того, что показывает os.getcwd()
. Но последующие вызовы os.getcwd()
покажут то же местоположение, что и первоначально.
Простое решение - разбить все ваши команды на их собственные subprocess.run()
вызовы. Но это тоже не сработает. Причина в том, что такие вещи, как cd
, не применяются к текущему сеансу, поэтому изменение рабочего каталога таким способом, на который вы надеетесь, не сработает.
Чтобы выполнить sh, используя несколько Для вызовов subprocess.run
потребуется комбинация subprocess
и некоторых функций в модуле os
. В частности, os.chdir()
. Но даже тогда вы можете столкнуться с аналогичными проблемами с другими командами и их аргументами.
Быстрый и грязный способ сделать это - собрать все команды вместе, разделенные точкой с запятой, но в виде одной строки (так же, как вы сделали бы в командной строке). Затем выполните его, используя аргумент shell=True
для run()
(что вы уже делаете). По сути, это:
myBashCommands = ["cd /Applications/MATLAB_R2018b.app/bin;"]
myBashCommands[0] += "./matlab -nodesktop;"
[....]
subprocess.run(myBashCommands,stderr=PIPE, stdout=PIPE, shell = True, check = True)
Как уже упоминалось в комментариях, здесь есть дополнительный уровень сложности, в котором размещенный код Python фактически содержит встроенный код Matlab. Есть 2 простых способа справиться с этим:
- поместить код Matlab в отдельный файл и использовать этот файл в качестве входных данных при вызове
matlab
. Что-то вроде этого, вероятно, будет работать:
myBashCommands = ["cd /Applications/MATLAB_R2018b.app/bin;"]
myBashCommands[0] += "./matlab -nodesktop run('/path/to/script/file.m');"
subprocess.run(myBashCommands,stderr=PIPE, stdout=PIPE, shell = True, check = True)
сохраните встроенный код Matlab внутри сценария python (мне это кажется несколько глупым), убедившись, что весь блок правильно заключен в кавычки и экранированы, и передайте его matlab в качестве аргумента командной строки:
myBashCommands = ["cd /Applications/MATLAB_R2018b.app/bin;"]
myBashCommands[0] += "./matlab -nodesktop 'potato_wav = audioread(\'potato-us.wav\'); [f, t, psd] = GetSpectrogram.m(\'potato_wav\', 16000, 10); smooth_psd = smoothn(10*log(psd), .5); smooth_psd = SurfaceCubicInterpolator(smooth_psd); dlmwrite(\'smooth_psd.csv\', smooth_psd, \'precision\', \',\', \'precision\', \'%.10f\')"
subprocess.run(myBashCommands,stderr=PIPE, stdout=PIPE, shell = True, check = True)