Skip to content

命令拼接类 CmdCache

DataAnalysisTableRecord类和TaskParam类中都通过cmd_cache属性封装了该类的一个实例。 在这两个类对应的使用场景中,都可以使用cmd_cacheadd方法来拼接命令,为了便于使用,这两个类通过同名函数透传调用了该方法, 即调用 record.add()|task_param.add() 等同于调用 record.cmd_cache.add()|task_param.cmd_cache.add()

使用cmd_cacheadd方法拼接好命令之后,可以调用record.run_scripts()|task_param.run_scripts()方法,该方法在cmd_cache.run()函数的基础上增加了额外的功能。建议开发人员不要直接调用 record.cmd_cache.run()|task_param.cmd_cache.run()run_scripts方法内部通过history_files删除了历史文件,并在执行命令时切换了命令执行所在的目录。

最后,值得说明的是record.clean_cache()|task_param.clean_cache() 方法,该方法透传调用了 cmd_cache.clean_cache(),作用是清除缓存里记录的之前的命令,如果业务里需要执行多条命令,在每次拼接命令之前需要调用该命令。

add 方法

record.add()|task_param.add() 等价于 CmdCache.add(scripts=default_null, key=default_null, value=default_null, ignore_default=None, r_bool_default=None):

  • scripts: default_null|str|list,调用脚本或功能名称
  • key: default_null|None|str,命令选项,如 -i,-c 等,可不存在
  • value: default_null|None|str,命令选项的值,如 infile.txt,red等,可不存在
  • ignore_default: None|str|bool,如果不为None,则当给定值与value值相同时,忽略拼接该参数。
  • r_bool_default: None|bool,如果不为None,则必须为bool类型,此时为将value转化成bool类型,并与其比较,不同则拼接到命令中,相同则忽略。

下面给出一些示例说明:

scripts,key,value三个参数不能同时为空,必须指定至少一个

1. 仅指定 scripts

from hippo.web.utils import CmdCache

cmd_cache = CmdCache()

cmd_cache.add(scripts="nvidia-smi") # 1.仅包含scripts (str)
cmd_cache.get_str()
# nvidia-smi 

cmd_cache.clean_cache()  # 清空之前的拼接命令缓存
cmd_cache.add(scripts=["sleep", "5"])  # 2.仅包含scripts (list);list 必须全为字符串
cmd_cache.get_str()
# sleep 5


cmd_cache.clean_cache()  # 清空之前的拼接命令缓存
cmd_cache.add(scripts="ls -l")  # 也可以直接将命令拼接好,不规范用法
cmd_cache.get_str()
# ls -l

# note: 指定scripts时,不能给空字符串, cmd_cache.add(scripts="") 会导致异常

2. 一些常见的命令行类型

scripts指定为脚本或命令名时,keyvalue参数有三种拼接的可能情形, 1. 没有value,此时仅指定key参数即可 2. 没有key,此时key=None 3. 同时存在,此时程序会对value参数在特殊情况下进行一些处理。详见下面代码示例中的说明


cmd_cache.clean_cache()  # 清空之前的拼接命令缓存
cmd_cache.add(scripts="ls")
cmd_cache.add(key="-l") # 没有value
cmd_cache.get_str()
# ls -l 

cmd_cache.clean_cache()  # 清空之前的拼接命令缓存
cmd_cache.add(scripts="sleep")
cmd_cache.add(key=None, value="5") # 没有key
cmd_cache.get_str()
# sleep 5


cmd_cache.clean_cache()  # 清空之前的拼接命令缓存
cmd_cache.add(scripts="demo_shell.sh")
cmd_cache.add(key="-i", value=1) # 支持 int
cmd_cache.add(key="-f", value=1.2) # 支持 float
cmd_cache.add(key="-b", value=True) # 支持 bool,拼接的值为True
cmd_cache.add(key="--title", value="main title") # 包含空格
cmd_cache.add(key="--sub-title", value="-log x^2") # 以-开头的参数,拼接中进行特殊处理
cmd_cache.add(key="--disc", value="&#;|") # 包含特殊字符
cmd_cache.add(key="--single", value="包含'引号") # 包含特殊字符
cmd_cache.add(key="--double", value='包含"引号') # 包含特殊字符
cmd_cache.get_str()
# demo_shell.sh -i 1 -f 1.2 -b True --title "main title" --sub-title="-log x^2" --disc "&#;|" --single "包含'引号" --double '包含"引号'

3. ignore_default的说明

cmd_cache.clean_cache() 
color = "red"  # or "yellow"
cmd_cache.add(key="-i", value="infile.txt")
cmd_cache.add(key="-c", value=color, ignore_default="red")
cmd_cache.get_str()
# color="red",则 
# demo.py -i infile.txt
# color="yellow",则 
# demo.py -i infile.txt -c yellow

4. r_bool_default 的说明

r_bool_default指定值必须为布尔类型,该参数一般用于R脚本的logical类型参数,当用户选择的参数和给定默认值相同,则最后的命令行会忽略拼接该参数。 与给定的值不同时,会传入R中需要的命令行参数(大写的TRUEFALSE


# type 1
cmd_cache.clean_cache() 
smooth_roc = False  # or True
cmd_cache.add("demo.r")
cmd_cache.add(key="-i", value="infile.txt")
cmd_cache.add(key="--smooth_roc", value=smooth_roc, r_bool_default=True)
cmd_cache.get_str()
# demo.r -i infile.txt --smooth_roc FALSE  ## when smooth_roc=False
# demo.r -i infile.txt                     ## when smooth_roc=True,忽略该参数


# type 2
cmd_cache.clean_cache() 
smooth_roc = False  # or True
cmd_cache.add("demo.r")
cmd_cache.add(key="-i", value="infile.txt")
cmd_cache.add(key="--smooth_roc", value=smooth_roc, r_bool_default=False)
cmd_cache.get_str()
# demo.r -i infile.txt                     ## when smooth_roc=False,忽略该参数
# demo.r -i infile.txt --smooth_roc FALSE  ## when smooth_roc=True

run_scripts 方法

在接口或者任务代码中请使用 .run_scripts()执行脚本命令,不要使用 .cmd_cache.run() 方法,这是因为就命令执行而言两者并无区别,但是 .run_scripts() 在业务代码和任务代码执行中增加了额外的处理,现就这些细节详细说明:

.run_scripts(self, history_files: str | List[str], force_use_dir=None, stdout=None, stderr=None)

  • history_files: str|list,参数接受一个文件路径,或多个文件路径的列表,执行命令之前会删除这些文件,注意只能删除 force_use_dir 路径下的文件
  • force_use_dir: None|str,参数为None时,默认使用工作空间下的output目录,可以指定其他执行目录,但不建议用户修改该输出目录
  • stdout: None|filestream,命令执行时使用的输出流,默认使用subprocess.PIPEfilestream可以是一个文件路径或一个文件流
  • stderr: None|filestream,命令执行时使用的错误流,默认使用subprocess.PIPEfilestream可以是一个文件路径或一个文件流

# 这里示意在业务代码中,任务代码中`.run_scripts()`的使用逻辑相同
@bp.route("/demo_code", methods=['POST'])
@platform_monitor()
def demo_code():
    record = DataAnalysisTableRecord(__file__)

    infile = record.get_input_param('infile')
    name = record.get_input_param('name')

    output = f"{name}.png"
    record.add(scripts="run.sh")
    record.add(key="-i",value=infile)
    record.add(key="-o",value=output)
    record.run_scripts(history_files=output)
    # note:
    # 1. 这里之所以可以使用相对路径,是因为 run_scripts 执行时默认拼接了进入 force_use_dir 目录的操作
    # 2. history_files 可以删除指定文件或文件列表,这里不支持正则匹配模式,如果输出文件是通过后缀匹配出来的,可以先执行匹配输出文件的逻辑得到文件列表传入
    pass

clean_cache 方法

.clean_cache() 只是清空之前拼接的命令行,一般只有在同一个业务过程中多次执行脚本才需要调用该方法。 该方法的逻辑比较简单,这里不在赘述。