68

Suppose that I have the following simple bash script which I want to submit to a batch server through SLURM:

#!/bin/bash

#SBATCH -o "outFile"$1".txt"
#SBATCH -e "errFile"$1".txt"

hostname

exit 0

In this script, I simply want to write the output of hostname on a textfile whose full name I control via the command-line, like so:

login-2:jobs$ sbatch -D `pwd` exampleJob.sh 1
Submitted batch job 203775

Unfortunately, it seems that my last command-line argument (1) is not parsed through sbatch, since the files created do not have the suffix I'm looking for and the string "$1" is interpreted literally:

login-2:jobs$ ls
errFile$1.txt  exampleJob.sh outFile$1.txt

I've looked around places in SO and elsewhere, but I haven't had any luck. Essentially what I'm looking for is the equivalent of the -v switch of the qsub utility in Torque-enabled clusters.

Edit: As mentioned in the underlying comment thread, I solved my problem the hard way: instead of having one single script that would be submitted several times to the batch server, each with different command line arguments, I created a "master script" that simply echoed and redirected the same content onto different scripts, the content of each being changed by the command line parameter passed. Then I submitted all of those to my batch server through sbatch. However, this does not answer the original question, so I hesitate to add it as an answer to my question or mark this question solved.

jeb
  • 78,592
  • 17
  • 171
  • 225
Jason
  • 2,495
  • 4
  • 26
  • 37
  • I do not know SLURM. Can you simplify the script into `touch outfile${1}.txt` lines, so we can try to reproduce the error and fix it? – Walter A Dec 30 '14 at 21:30
  • The 1 is passed to the script but is not considered for the name of the files as slurm preprocesses the file to get the flags, but the variable should be available inside the script. How do you do that on Torque? – Carles Fenoy Dec 30 '14 at 21:52
  • @WalterA: Your solution worked in the case of `touch`, that is, the argument I pass through `sbatch`is correctly read by the script as `$1`. However, it appears that `$1` is parsed literally by `sbatch` in the case of `-o` and `-e`, such that I end up with files such as `outFile${1}.txt`on disk. @CarlesFenoy: I believe you are correct in what you are saying in that SLURM pre-processes the file to get the `-o` and `-e` flags (see my response to @WalterA above as well). In Torque, you could do something like `qsub -D 'pwd' -v var=1 script.sh` and `$var` would have the value of 1 in `script.sh`. – Jason Dec 30 '14 at 22:16
  • I should also mention that I solved my problem the hard way, that is, creating a bunch of scripts with a "master script" that simply echoed lots of lines of content to reflect all the different command line parameters that I wanted to pass to a single script, and then submitted them all to my batch server through `sbatch`. This, however, does not answer the question at hand, so I hesitate to add it as my own answer to the original question. I will also make an edit in the original post to reflect this. – Jason Dec 30 '14 at 22:18

7 Answers7

35

I thought I'd offer some insight because I was also looking for the replacement to the -v option in qsub, which for sbatch can be accomplished using the --export option. I found a nice site here that shows a list of conversions from Torque to Slurm, and it made the transition much smoother.

You can specify the environment variable ahead of time in your bash script:

$ var_name='1'
$ sbatch -D `pwd` exampleJob.sh --export=var_name

Or define it directly within the sbatch command just like qsub allowed:

$ sbatch -D `pwd` exampleJob.sh --export=var_name='1'

Whether this works in the # preprocessors of exampleJob.sh is also another question, but I assume that it should give the same functionality found in Torque.

MasterHD
  • 2,264
  • 1
  • 32
  • 41
  • 15
    To save others the troubleshooting, `--export=var_name` didn't work for me, I had to use --export=var_name='1'`. Also, I had to put `--export=var_name="1"` before the path to my script; it didn't work as arranged in this answer. – Josh May 21 '20 at 19:34
  • 2
    This worked for me: ```sbatch -D `pwd` --export=var_name=$var_name exampleJob.sh``` – Yacine Mahdid May 30 '20 at 00:49
  • 3
    What worked for me was `sbatch --export=ALL,var_name='1' exampleJob.sh` Without the `ALL` SLURM creates a new environment, separate from the user's environment. – Reed Espinosa Aug 27 '20 at 21:25
  • @Josh thank you putting the flag before the script path worked for me to! – joshua Apr 06 '21 at 17:02
30

Using a wrapper is more convenient. I found this solution from this thread.

Basically the problem is that the SBATCH directives are seen as comments by the shell and therefore you can't use the passed arguments in them. Instead you can use a here document to feed in your bash script after the arguments are set accordingly.

In case of your question you can substitute the shell script file with this:

#!/bin/bash
sbatch <<EOT
#!/bin/bash

#SBATCH -o "outFile"$1".txt"
#SBATCH -e "errFile"$1".txt"

hostname

exit 0
EOT

And you run the shell script like this:

bash [script_name].sh [suffix]

And the outputs will be saved to outFile[suffix].txt and errFile[suffix].txt

PouyaB
  • 749
  • 7
  • 6
24

If you pass your commands via the command line, you can actually bypass the issue of not being able to pass command line arguments in the batch script. So for instance, at the command line :

var1="my_error_file.txt"
var2="my_output_file.txt"
sbatch --error=$var1 --output=$var2 batch_script.sh
irritable_phd_syndrome
  • 4,631
  • 3
  • 32
  • 60
7

The lines starting with #SBATCH are not interpreted by bash but are replaced with code by sbatch. The sbatch options do not support $1 vars (only %j and some others, replacing $1 by %1 will not work). When you don't have different sbatch processes running in parallel, you could try

#!/bin/bash

touch outFile${1}.txt errFile${1}.txt
rm link_out.sbatch link_err.sbatch 2>/dev/null # remove links from previous runs
ln -s outFile${1}.txt link_out.sbatch
ln -s errFile${1}.txt link_err.sbatch

#SBATCH -o link_out.sbatch
#SBATCH -e link_err.sbatch

hostname
# I do not know about the background processing of sbatch, are the jobs still running
# at this point? When they are, you can not delete the temporary symlinks yet.

exit 0

Alternative: As you said in a comment yourself, you could make a masterscript. This script can contain lines like

cat  exampleJob.sh.template | sed -e 's/File.txt/File'$1'.txt/' > exampleJob.sh
# I do not know, is the following needed with sbatch?
chmod +x exampleJob.sh

In your template the #SBATCH lines look like

#SBATCH -o "outFile.txt"
#SBATCH -e "errFile.txt"
Walter A
  • 19,067
  • 2
  • 23
  • 43
  • Thank you! Essentially this solution allows sbatch's code to operate on soft links, but the links themselves point to actual files created by the portion of the shell script that can properly parse command line arguments. I will accept this as my answer. – Jason Dec 31 '14 at 15:40
  • 1
    This will not work as #SBATCH parameters must appear [before any other command otherwise they are ignored](http://slurm.schedmd.com/sbatch.html) – damienfrancois Feb 12 '16 at 20:59
  • @damienfrancois You might be right, I have not actually tried it with Slurm. I looked at your link, and I think my script should be split into a part used by Slurm (with only #SBATCH lines) and a mainscript that will call Slurm. That masterscript should detach itself from his child and does not know when to clean up the temporary links. So I guess the alternative solution (with a template) I gave works better. Do you know if you can put Shell Variables in a `` ? Something like `--output=File${some_var}.out` or `--output=File${myshell.sh}.out`? – Walter A Feb 12 '16 at 21:39
  • Only if you pass the submission script through stdin to `sbatch` rather than supplying it in as an argument. – damienfrancois Feb 15 '16 at 08:35
2

This is an old question but I just stumbled into the same task and I think this solution is simpler:

Let's say I have the variable $OUT_PATH in the bash script launch_analysis.bash and I want to pass this variable to task_0_generate_features.sl which is my SLURM file to send the computation to a batch server. I would have the following in launch_analysis.bash:

`sbatch --export=OUT_PATH=$OUT_PATH task_0_generate_features.sl`

Which is directly accessible in task_0_generate_features.sl

In @Jason case we would have:

sbatch -D `pwd` --export=hostname=$hostname exampleJob.sh

Reference: Using Variables in SLURM Jobs

Yacine Mahdid
  • 723
  • 5
  • 17
1

Something like this works for me and Torque

echo "$(pwd)/slurm.qsub 1" | qsub -S /bin/bash -N Slurm-TEST
slurm.qsub:

#!/bin/bash
hostname > outFile${1}.txt 2>errFile${1}.txt
exit 0
ndnenkov
  • 35,425
  • 9
  • 72
  • 104
1

The easiest way I have found is to use the --wrap argument to sbatch. E.g., instead of this:

sbatch -D `pwd` exampleJob.sh 1

..do this:

sbatch -D `pwd` --wrap="exampleJob.sh 1"

...and then SLURM will generate its own wrapper behind the scenes.

chris c
  • 11
  • 1