subprocess:python中執(zhí)行外部命令

1. 簡(jiǎn)介

subprocess 是 Python 的一個(gè)標(biāo)準(zhǔn)庫(kù),它允許你啟動(dòng)新的進(jìn)程、連接到它們的輸入/輸出/錯(cuò)誤管道,并且獲取它們的返回值。
該庫(kù)使 Python 程序能夠方便地與操作系統(tǒng)交互,執(zhí)行系統(tǒng)命令,調(diào)用外部程序,處理子進(jìn)程,使得在 Python 程序中運(yùn)行外部命令和程序變得簡(jiǎn)單和靈活。

2. 主要方法

  • subprocess.run():運(yùn)行指定的命令并等待其完成,返回一個(gè) CompletedProcess 實(shí)例。
  • subprocess.Popen():創(chuàng)建一個(gè)新的進(jìn)程,可以進(jìn)行更復(fù)雜的交互;
  • subprocess.call():運(yùn)行命令并等待其完成,命令出錯(cuò)時(shí)拋出異常;
  • subprocess.check_call():運(yùn)行命令并等待其完成,命令返回非零退出狀態(tài)時(shí)拋出異常;
  • subprocess.check_output():運(yùn)行命令,捕獲輸出,如果命令失敗則拋出異常。

注意:
subprocess.run() 默認(rèn)情況下不會(huì)捕獲實(shí)時(shí)輸出,它會(huì)等待命令執(zhí)行完成后才返回。
subprocess.Popen() 允許你實(shí)時(shí)地從 stdout 和 stderr 中讀取輸出,但要寫一個(gè)簡(jiǎn)單的循環(huán)代碼,這個(gè)循環(huán)會(huì)持續(xù)從 stdout 中讀取,直到?jīng)]有更多輸出,并且進(jìn)程已經(jīng)結(jié)束。

3. 簡(jiǎn)單實(shí)例

import subprocess

3.1. 執(zhí)行ls -l命令

# 執(zhí)行 ls -l 命令
result = subprocess.run(['ls', '-l'], capture_output=True, text=True)

# 打印輸出結(jié)果
print("STDOUT:", result.stdout)
if result.stderr:  # 如果存在錯(cuò)誤則輸出
    print("STDERR:", result.stderr)
image.png

3.2. 執(zhí)行echo命令并傳遞參數(shù)

# 執(zhí)行 echo 命令并傳遞字符串參數(shù)
result = subprocess.run(['echo', 'Hello, World!'], capture_output=True, text=True)

# 打印輸出結(jié)果
print("STDOUT:", result.stdout)
image.png

3.3. 在 Python 腳本中執(zhí)行其他 Python 腳本

# 執(zhí)行另一個(gè) Python 腳本
result = subprocess.run(['python', 'other_script.py'], capture_output=True, text=True)

# 打印其他腳本的輸出
print("STDOUT:", result.stdout)

3.4. 實(shí)時(shí)執(zhí)行命令并獲取輸出

# 實(shí)時(shí)執(zhí)行 tail -f 命令(假設(shè)有一個(gè)日志文件 log.txt)
with subprocess.Popen(['tail', '-f', 'log.txt'], stdout=subprocess.PIPE, text=True) as process:
    for line in process.stdout:
        print(line.strip())  # 實(shí)時(shí)打印每一行輸出
        # 如果需要停止實(shí)時(shí)輸出,可以使用 process.terminate() 或 process.kill()

4. 復(fù)雜實(shí)例

4.1 非實(shí)時(shí)輸出中間信息

LigandMPNN是一個(gè)項(xiàng)目的根路徑,內(nèi)部包含了可執(zhí)行python文件run.py,其命令行模式的執(zhí)行方式如下:

conda activate 對(duì)應(yīng)python環(huán)境  # 進(jìn)入針對(duì)該項(xiàng)目的python環(huán)境(如果有的話)

cd /home/houliya/LigandMPNN  # 進(jìn)入項(xiàng)目根路徑

# 直接linux終端執(zhí)行或把下面代碼寫入shell文件再執(zhí)行
python run.py \
        --model_type "ligand_mpnn" \
        --seed 111 \
        --pdb_path "/home/houliya/protein_desig_cgx/output_cgx/output_luciferase_RFDAA_all_new/nnluz_RFAA_RFDAA_4.pdb" \
        --out_folder "/home/houliya/protein_desig_cgx/output_test" \
        --pack_side_chains 1 \
        --number_of_packs_per_design 2 \
        --pack_with_ligand_context 1 \
        --file_ending "_ligandMPNN" \
        --batch_size 1 \
        --number_of_batches 2

如何將其在python中執(zhí)行這些代碼,并得到相同的結(jié)果?由于不需要輸出實(shí)時(shí)的計(jì)算信息,因此利用subprocess.run()方法:

result = subprocess.run(['python','run.py',
                        "--model_type", "ligand_mpnn",
                        "--seed", "111",
                        "--pdb_path", "/home/houliya/protein_desig_cgx/output_cgx/output_luciferase_RFDAA_all_new/nnluz_RFAA_RFDAA_4.pdb",
                        "--out_folder", "/home/houliya/protein_desig_cgx/output_test",
                        "--pack_side_chains", "1",
                        "--number_of_packs_per_design", '2',
                        "--file_ending", "_ligandMPNN",
                        "--batch_size", "1",
                        "--number_of_batches", "2"], capture_output=True, text=True)

if result.stderr:  # 判斷是否有錯(cuò)誤信息
    print(result.stderr)

if result.stdout:  # 輸出一些結(jié)果信息
    print(result.stdout)

if result.check_returncode:  # 輸出一些返回信息
    print(result.check_returncode)

4.2 實(shí)時(shí)輸出計(jì)算過程中的每一步信息

rf_diffusion_all_atom是一個(gè)項(xiàng)目的根路徑,該項(xiàng)目包含了一個(gè)名為rf_se3_diffusion.sif的apptainer容器文件,要執(zhí)行對(duì)應(yīng)的python代碼run_inference.py,必須先啟動(dòng)容器,且代碼執(zhí)行過程中會(huì)實(shí)時(shí)輸出相應(yīng)信息,因此整體比例4.1更復(fù)雜,先來看常規(guī)命令行的執(zhí)行方式:

conda activate 對(duì)應(yīng)python環(huán)境  # 進(jìn)入針對(duì)該項(xiàng)目的python環(huán)境(如果有的話)

cd /home/houliya/rf_diffusion_all_atom  # 進(jìn)入項(xiàng)目根路徑

# 直接linux終端執(zhí)行或把下面代碼寫入shell文件再執(zhí)行
apptainer run --nv rf_se3_diffusion.sif -u run_inference.py \
        inference.deterministic=True \
        diffuser.T=100 \
        inference.output_prefix=/home/houliya/protein_desig_cgx/output_test/nnluz_RFAA_RFDAA \
        inference.input_pdb=/home/houliya/protein_desig_cgx/input_cgx/input_luciferase/nnluz_RFAA.pdb \
        contigmap.contigs=[\'266-266\'] \
        inference.ligand=LG1 \
        inference.num_designs=500 \
        inference.design_startnum=1

如何將其在python中執(zhí)行這些代碼,并得到相同的結(jié)果?由于需要輸出實(shí)時(shí)的計(jì)算信息,因此利用subprocess.Popen()方法:

process = subprocess.Popen(['apptainer','run',
                        "--nv", "rf_se3_diffusion.sif",
                        "-u", "run_inference.py",
                        "inference.deterministic=True",
                        "diffuser.T=100",
                        "inference.output_prefix=/home/houliya/protein_desig_cgx/output_test/nnluz_RFAA_RFDAA",
                        "inference.input_pdb=/home/houliya/protein_desig_cgx/input_cgx/input_luciferase/nnluz_RFAA.pdb",
                        "contigmap.contigs=[\'266-266\']",
                        "inference.ligand=LG1",
                        "inference.num_designs=500",
                        "inference.design_startnum=1"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)


# 循環(huán)讀取輸出直到?jīng)]有更多輸出
while True:
    output = process.stdout.readline()
    if output == '' and process.poll() is not None:
        break
    if output:
        print(output.strip())  # 打印輸出,去除末尾的換行符

# 等待進(jìn)程結(jié)束
stdout, stderr = process.communicate()

# 檢查是否有錯(cuò)誤輸出
if stderr:
    print("STDERR:")
    print(stderr)
image.png

5. 需要注意的地方:

從shell代碼轉(zhuǎn)換到subprocess.run()或subprocess.Popen()代碼時(shí)的輸入?yún)?shù)的寫法。
例如shell中某個(gè)輸入?yún)?shù)寫為--seed 111,而在subprocess.run()中寫成了"--seed", "111";
又例如在shell中某個(gè)輸入?yún)?shù)寫為diffuser.T=100,而在subprocess.Popen()中寫成了"diffuser.T=100"
subprocess.run()或subprocess.Popen()中只能輸入字符串,而不能輸入int、float等其他類型!

6. 其他

https://cloud.tencent.com/developer/article/2291501
https://blog.csdn.net/Htojk/article/details/134048843

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容