drmaaによるqsubコマンドのシェル変数の拡張

drmaaによるqsubコマンドのシェル変数の拡張

次のコマンドを使用して Sun Grid Engine (SGE) にバッチジョブの送信を実行しています。Python drmaaバインディング

バッチジョブの送信の場合は、パラメータを受け入れ、shebangを介してコマンドラインから実行可能なPythonスクリプトを送信します。タスクバッチ送信を適切にパラメータ化するために、optionsを介してPythonスクリプトに伝播するように環境変数を設定しました-v。ジョブの送信中にエクスポートされたSGE /環境変数に基づいて$TASK_IDzsh環境で間接変数拡張を実行しようとしています。$SGE_TASK_ID

間接変数拡張の最小限の再現可能な例として、同様のことを試みており、私のシェルで動作します。

export foo1=2
export num=1

echo $(tmp=foo$num; echo ${(P)tmp})

生産する2

サンプルスクリプトjob_script.py

#! /usr/bin/python
import argparse
import os

parser = argparse.ArgumentParser()
parser.add_argument("input_path", type=os.path.realpath)

def main(input_path):
    # do stuff
    ...

if __name__ == "__main__":
    args = parser.parse_args
    input_path = args.input_path
    main(input_path)

drmaa 送信スクリプトの例


import os

# add path to libs
os.environ["DMRAA_LIBRARY_PATH"] = "path to DMRAA shared object"
os.environ["SGE_ROOT"] = "path to SGE root directory"
import drmaa

input_dir_suffixes = [1, 2, 5, 7, 10, 11]

INPUT_BASE_DIR = "/home/mel/input_data"

base_qsub_options = {
    "P": "project",
    "q": "queue",
    "b": "y", # means is an executable
    "shell": "y", # start up shell
}
native_specification = " ".join(f"-{k} {v}" for k,v in base_qsub_options.items())
remote_command = "job_script.py"

num_task_ids = len(input_dir_suffixes)
task_start = 1
task_stop = num_task_ids + 1
task_step = 1
task_id_zip = zip(range(1, num_task_ids + 1), input_dir_suffixes) 
task_id_env_vars = {
   f"TASK_ID_{task_id}_SUFFIX": str(suffix) for task_id, suffix in task_id_zip 
}

io_task_id = r"$(tmp=SUFFIX_TASK_ID_$TASK_ID; echo ${(P)tmp)})"
arg_task_id = r"$(tmp=SUFFIX_TASK_ID_$SGE_TASK_ID; echo ${(P)tmp)})"

with drmaa.Session() as session:
    
    template = session.createJobTemplate()
    template.nativeSpecification = native_specification
    template.remoteCommand = remote_command
    template.jobEnvironment = task_id_env_vars
    template.outputPath = f":{INPUT_BASE_DIR}/output/{io_task_id}.o"
    template.outputPath = f":{INPUT_BASE_DIR}/error/{io_task_id}.e"

    args_list = [f"{INPUT_BASE_DIR}/data{arg_task_id}"]
    template.args = args_list
    session.runBulkJobs(template, task_start, task_stop - 1, task_step)
    session.deleteJobTemplate(template)

構文エラーがある場合は申し訳ありません。別のシステムにあるため、手動でコピーする必要がありました。

提出完了後

職場のqstat -j電話番号だと

次の設定が表示されます

sge_o_shell:         /usr/bin/zsh
stderr_path_list:    NONE:<node>:/home/mel/input_data/error_log/$(tmp=SUFFIX_TASK_ID_$TASK_ID; echo ${(P)tmp}).e
stdout_path_list:    NONE:<node>:/home/mel/input_data/output_log/$(tmp=SUFFIX_TASK_ID_$TASK_ID; echo ${(P)tmp}).o
job_args:            /home/mel/input_data/data$(tmp=SUFFIX_TASK_ID$SGE_TASK_ID; echo ${(P)tmp})
script_file:         job_script.py

env_list: 
SUFFIX_TASK_ID_1=1,SUFFIX_TASK_ID_2=2,SUFFIX_TASK_ID_3=5,SUFFIX_TASK_ID_4=7,SUFFIX_TASK_ID_5=10,SUFFIX_TASK_ID_6=11

エラーログと出力ログは別々に生成されますが、部分的にのみ拡張されます。

はい

$(tmp=SUFFIX_TASK_ID1; echo ${(P)tmp}).e
$(tmp=SUFFIX_TASK_ID1; echo ${(P)tmp}).o

catエラーログを見るとIllegal variable name

私がしたいことが可能なことですか?

だから、どこかで私のzshが正しくアクティブになっていないとします。

答え1

SGEはBourneシェル(/bin/sh)を作業スクリプトのデフォルトシェルとして使用します。これにより、他のシェルの特定の機能や構文に依存するスクリプトに問題が発生する可能性があります。あなたの場合は、zsh関数(を使用したパラメータ拡張)を使用しようとしています${(P)tmp}

問題は、DRMAA操作で実行したいシェル変数の拡張に関するものです。${(P)tmp}ジョブがSGEに送信されると、間接変数拡張()が正しく認識されないようです。

ここではログインシェルはzshsge_o_shell: /usr/bin/zsh)ですが、シェルは説明するqsubコマンドラインパラメータとDRMAAジョブ送信パラメータはzsh。この${(P)tmp}構文はのみ適用され、これらの引数を解釈するシェルである可能性があるzsh他のシェルでは機能しません。bashsh

-vしたがって、DRMAAスクリプトでオプション(環境変数渡し)とコマンド置換()を使用してジョブを送信すると、$(...)SGEはコマンドの対応する部分を解釈するために使用されない可能性があり、zshそのzshため特定の構文は機能しません。

これは、変数拡張を実行するためにラッパースクリプトを生成し、結果とともにzshPythonスクリプトを呼び出す必要があることを意味します。ラッパースクリプトはジョブスクリプトとして送信され、経由zshで実行するときに機能を使用できますzsh

#!/usr/bin/env zsh

# use zsh for variable expansion
suffix=$(tmp=SUFFIX_TASK_ID_$TASK_ID; echo ${(P)tmp})

# call the python script with the result(s)
exec /path/to/job_script.py /home/mel/input_data/data$suffix

DRMAAスクリプト内のジョブとしてラッパースクリプトを送信し、以下を使用して実行することを指定しますzsh

...
# path to the wrapper script
remote_command = "/path/to/wrapper_script.zsh"

...
# specify that the job should be run with zsh
base_qsub_options = {
    ...
    "shell": "/usr/bin/zsh",
    ...
}
...

気づく:必要に応じて調整する必要があります。

関連情報