如何获取用于 SLURM 作业的脚本的原始位置?

How to get original location of script used for SLURM job?

我正在使用脚本启动 SLURM 作业,脚本必须根据其位置工作,该位置是使用 SCRIPT_LOCATION=$(realpath [=13=]) 在脚本本身内部获得的。但是 SLURM 将脚本复制到 slurmd 文件夹并从那里开始工作,它搞砸了进一步的操作。

是否有任何选项可以在 moved/copied 之前获取用于 slurm 作业的脚本的位置?

脚本位于网络共享文件夹 /storage/software_folder/software_name/scripts/this_script.sh 中,它必须:

  1. 获取它自己的位置
  2. return software_name 文件夹
  3. software_name 文件夹复制到节点 /node_folder 上的本地文件夹
  4. 运行 复制文件夹中的另一个脚本 /node_folder/software_name/scripts/launch.sh

我的剧本是

#!/bin/bash
#SBATCH --nodes=1
#SBATCH --partition=my_partition_name

# getting location of software_name 
SHARED_PATH=$(dirname $(dirname $(realpath [=10=])))
# separating the software_name from path
SOFTWARE_NAME=$(basename $SHARED_PATH)
# target location to copy project
LOCAL_SOFTWARE_FOLDER='/node_folder'
# corrected path for target
LOCAL_PATH=$LOCAL_SOFTWARE_FOLDER/$SOFTWARE_NAME

# Copying software folder from network storage to local
cp -r $SHARED_PATH $LOCAL_SOFTWARE_FOLDER
# running the script
sh $LOCAL_PATH/scripts/launch.sh

它 运行 非常完美,当我 运行 它在节点本身上时(不使用 SLURM)通过:sh /storage/software/scripts/this_script.sh.

如果运行使用 SLURM 作为 sbatch /storage/software/scripts/this_script.sh 它被分配给其中一个节点,但是:

当使用 SLURM 启动时,是否可以在脚本内部获取原始位置 (/storage/software_folder/software_name/)?

P.S。所有机器都是 运行ning Fedora 30 (x64)

更新 1

有人建议将 运行 作为 sbatch -D /storage/software_folder/software_name ./scripts/this_script.sh 并在脚本本身内部使用 SHARED_PATH="${SLURM_SUBMIT_DIR}"。 但它引发了错误 sbatch: error: Unable to open file ./scripts/this_script.sh.

此外,我尝试使用绝对路径: sbatch -D /storage/software_folder/software_name /storage/software_folder/software_name/scripts/this_script.sh。它尝试 运行,但是:

还有其他建议吗?

更新 2: 还尝试在脚本内部使用 #SBATCH --chdir=/storage/software_folder/software_name,但在这种情况下 echo "${SLURM_SUBMIT_DIR}" returns /home/username_who_started_script/(如果 运行 作为 root)

更新 3

仅当任务为 运行 时,使用 ${SLURM_SUBMIT_DIR} 的方法才有效:

cd /storage/software_folder/software_name
sbatch ./scripts/this_script.sh

但这似乎不是一个合适的解决方案。还有其他方法吗?

解决方案

#!/bin/bash
#SBATCH --nodes=1
#SBATCH --partition=my_partition_name

# check if script is started via SLURM or bash
# if with SLURM: there variable '$SLURM_JOB_ID' will exist
# `if [ -n $SLURM_JOB_ID ]` checks if $SLURM_JOB_ID is not an empty string
if [ -n $SLURM_JOB_ID ];  then
    # check the original location through scontrol and $SLURM_JOB_ID
    SCRIPT_PATH=$(scontrol show job $SLURM_JOBID | awk -F= '/Command=/{print }')
else
    # otherwise: started with bash. Get the real location.
    SCRIPT_PATH=$(realpath [=12=])
fi

# getting location of software_name 
SHARED_PATH=$(dirname $(dirname $(SCRIPT_PATH)))
# separating the software_name from path
SOFTWARE_NAME=$(basename $SHARED_PATH)
# target location to copy project
LOCAL_SOFTWARE_FOLDER='/node_folder'
# corrected path for target
LOCAL_PATH=$LOCAL_SOFTWARE_FOLDER/$SOFTWARE_NAME

# Copying software folder from network storage to local
cp -r $SHARED_PATH $LOCAL_SOFTWARE_FOLDER
# running the script
sh $LOCAL_PATH/scripts/launch.sh

在脚本中,将 SHARED_PATH 作为 SHARED_PATH="${SLURM_SUBMIT_DIR}"

将脚本提交为 sbatch -D /storage/software ./scripts/this_script.sh

参见 here

来自参考页面:

-D

Set the working directory of the batch script to directory before it is executed. The path can be specified as full path or relative path to the directory where the command is executed.

SLURM_SUBMIT_DIR

The directory from which sbatch was invoked or, if applicable, the directory specified by the -D, --chdir option.

P.S. 以上来自版本 19.05 doc.
在查看存档时,参考版本。 18.x(尤其是 18.08),它没有提到相同的内容。参见 this

SLURM_SUBMIT_DIR

The directory from which sbatch was invoked.

您可以像这样从 scontrol 获取提交脚本的初始(即在提交时)位置:

scontrol show job $SLURM_JOBID | awk -F= '/Command=/{print }'

所以你可以用上面的替换realpath [=14=]部分。当然,这仅适用于 Slurm 分配。因此,如果您希望脚本在任何情况下都能正常工作,您将需要一些逻辑,例如:

if [ -n $SLURM_JOB_ID ] ; then
THEPATH=$(scontrol show job $SLURM_JOBID | awk -F= '/Command=/{print }')
else
THEPATH=$(realpath [=11=])
fi

然后继续

SHARED_PATH=$(dirname $(dirname "${THEPATH}"))

我必须在数组作业中做同样的事情, 接受的答案适用于所有作业,除了与 ArrayJobId 相同的 jobid。只需将 awk 命令传递给 head 命令就可以了

scontrol show job $SLURM_JOBID | awk -F= '/Command=/{print }' | head -n 1