python实现批量运行命令行

python实现批量运行命令行

背景:

对于不同参数设置来调用同一个接口,如果手动一条条修改再运行非常慢且容易出错。尤其是这次参数非常多且长。比如之前都是输入nohup python -u exe.py >> ../log/exp3.log 2>&1 & 来运行一次,在exe中会设置参数并调用接口运行preditction_uni(input_file_path, sheet_name, output_file_path, pic_path, cols_x, cols_y, n_jobs, sheet_name_res),由于每次这些参数都不同但又有一定的规律,所以可以尝试批量运行。

解决方法:

使用python的subprocess

文件结构是:

|--cmd_exe.py

--exe.py

--exp3.py

--interface.py

exp3.py中设置参数并调用interface.py中的接口,exe.py中是主函数调用exp3.py启动运行。

现在修改了exp3.py中代码,循环的使用不同参数来带入subprocess,进而调用cmd_exe.py执行原本要在terminal中执行的指令。这样把原本在exp3.py中调用接口preditction_uni部分挪到新的cmd_exe.py中,exp3,py中增加command循环调用的代码来实现批量执行。

# exp3.py 部分代码

import subprocess
# ...
# 设置参数
# ···
n_jobs = int(5)
cols_x_str = f'"{cols_xs}"'

commmand = f"nohup python -u cmd_exe.py {input_file_path} {sheet_name} {output_file_path} {pic_path} {cols_x_str} {cols_y} {n_jobs} {sheet_name_res} >> ../log/exp3/{log_name}.log 2>&1 &"

print(commmand) # 一般会打印命令
subprocess.Popen(commmand, shell=True)
# cmd_exe.py 代码

import sys
import exp3
import ast


if __name__ == '__main__':
    input_file_path = sys.argv[1]
    sheet_name = sys.argv[2]
    output_file_path = sys.argv[3]
    pic_path = sys.argv[4]
    cols_x = ast.literal_eval(sys.argv[5])
    cols_y = sys.argv[6]
    n_jobs = sys.argv[7]
    sheet_name_res = sys.argv[8]

    exp3.preditction_uni(input_file_path, sheet_name, output_file_path, pic_path, cols_x, cols_y, n_jobs, sheet_name_res)
  • 传参数问题1:

    exp3.py中我想传给调用的preditction_uni函数参数有数字和包含多个字符串的数组。示例如下。

    n_jobs = 5 
    cols_xs = ['参数1', '参数2','参数1', '参数2','参数1', '参数2']
    

    但是在执行后会出现错误:

    Traceback (most recent call last):
      File "/home/P.py", line 11, in <module>
        cols_x = ast.literal_eval(sys.argv[5])
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "/home/anaconda3/envs/python310/lib/python3.11/ast.py", line 64, in literal_eval
        node_or_string = parse(node_or_string.lstrip(" \t"), mode='eval')
                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "/home/anaconda3/envs/python310/lib/python3.11/ast.py", line 50, in parse
        return compile(source, filename, mode, flags,
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "<unknown>", line 1
        [参数1,
        ^
    SyntaxError: '[' was never closed
    

    尝试使用ast.literal_eval()来解析,但是不行。cols_xs 是一个包含多个字符串元素的列表。通过argv来传递字符串列表是解析出来只有第一个元素。所以想把整个字符串列表都传过来那么要把整个列表作为一个字符串,即在外面再包一个双引号f'"{cols_xs}"'

  • 传参数问题2:

    Traceback (most recent call last):
      ...
      File "/home/P.py", line 179, in post_run
        y_pred_test, y_pred_prob_test, b_solver, b_c = train_model_Grid(estimator, param, cv=5, X_train=X_train_std, X_test=X_test_std, y_train=y_train, n_jobs=n_jobs)
                                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ...
    validate_parameter_constraints
        raise InvalidParameterError(
    sklearn.utils._param_validation.InvalidParameterError: The 'n_jobs' parameter of GridSearchCV must be an instance of 'int' or None. Got '5' instead.
    

    传的参数是一个字符串类型,即使它表示一个整数值。使用n_jobs = int(5)

    通过 sys.argv 传递的参数是字符串类型(str)。sys.argv 是一个列表,其中包含了命令行参数的字符串表示形式。列表的第一个元素是执行 Python 脚本的文件路径,后续元素是命令行中提供的参数。

    如果需要将其解析为其他类型,例如整数或浮点数,需要使用相应的转换函数(例如 int()float())进行转换。

sys传参数

通过 sys.argv 传递的参数是字符串类型(str)

示例程序:

# test.py

import subprocess
import test1

nums = [1, 2, 3]

input_file_path = '../python/data'

n_jobs = 6

col_x =[
    ['test', 'is', 'just', 'a', 'demo'],
    ['tomorrow', 'never', 'wait', 'for', 'you'],
    ['just', 'do', 'it', 'now']
]

cols = zip(nums, col_x)

for num, colx in cols:
    # colx = f'"{colx}"'
    command = f"python -u test1.py {input_file_path} {n_jobs} {colx} >> ./test.log 2>&1 &"

    print(command)

    subprocess.Popen(command, shell=True)

    print(f"process {num} is running")
# test1.py
import sys

if __name__ == '__main__':

    print(f"sys.argv[0] = {sys.argv[0]} , type = {type(sys.argv[0])}")
    print(f"sys.argv[1] = {sys.argv[1]} , type = {type(sys.argv[1])}")
    print(f"sys.argv[2] = {sys.argv[2]} , type = {type(sys.argv[2])}")
    print(f"sys.argv[3] = {sys.argv[3]} , type = {type(sys.argv[3])}")
python test.py

结果:

python -u test1.py ../python/data 6 ['test', 'is', 'just', 'a', 'demo'] >> ./test.log 2>&1 &
process 1 is running
python -u test1.py ../python/data 6 ['tomorrow', 'never', 'wait', 'for', 'you'] >> ./test.log 2>&1 &
process 2 is running
python -u test1.py ../python/data 6 ['just', 'do', 'it', 'now'] >> ./test.log 2>&1 &
process 3 is running

# test.log
sys.argv[0] = test1.py , type = <class 'str'>
sys.argv[1] = ../python/data , type = <class 'str'>
sys.argv[2] = 6 , type = <class 'str'>
sys.argv[3] = [tomorrow, , type = <class 'str'>
sys.argv[0] = test1.py , type = <class 'str'>
sys.argv[1] = ../python/data , type = <class 'str'>
sys.argv[2] = 6 , type = <class 'str'>
sys.argv[3] = [test, , type = <class 'str'>
sys.argv[0] = test1.py , type = <class 'str'>
sys.argv[1] = ../python/data , type = <class 'str'>
sys.argv[2] = 6 , type = <class 'str'>
sys.argv[3] = [just, , type = <class 'str'>

在 command 之前增加colx = f'"{colx}"',之后的效果:

# test.log

sys.argv[1] = ../python/data , type = <class 'str'>
sys.argv[2] = 6 , type = <class 'str'>
sys.argv[3] = ['test', 'is', 'just', 'a', 'demo'] , type = <class 'str'>
sys.argv[0] = test1.py , type = <class 'str'>
sys.argv[1] = ../python/data , type = <class 'str'>
sys.argv[2] = 6 , type = <class 'str'>
sys.argv[3] = ['tomorrow', 'never', 'wait', 'for', 'you'] , type = <class 'str'>
sys.argv[0] = test1.py , type = <class 'str'>
sys.argv[1] = ../python/data , type = <class 'str'>
sys.argv[2] = 6 , type = <class 'str'>
sys.argv[3] = ['just', 'do', 'it', 'now'] , type = <class 'str'>
posted @ 2024-03-10 17:55  ben犇  阅读(381)  评论(0编辑  收藏  举报