A job script tells Slurm what your job needs (cores, memory, time, queue) and what to run. Write it once, submit it with sbatch, and Slurm runs it on a compute node when resources are free. This page gives you a template to copy, explains each part, and lists the options you'll use most.
On this page: The four parts ยท Template ยท Asking for resources ยท Directive reference ยท Useful variables ยท Dependencies ยท Make scripts safer ยท Troubleshooting
module load slurm before using sbatch.The four parts of a job script
- Shebang line:
#!/bin/bash, so the script runs in bash. - #SBATCH lines: what the job needs. Slurm reads these; bash treats them as comments.
- Environment setup: load modules and set variables.
- The work: the commands that actually run.
Template
#!/bin/bash # --- Job identification --- #SBATCH --job-name=my_job #SBATCH --output=%x_%j.out # %x = job name, %j = job ID #SBATCH --error=%x_%j.err # --- Resources --- #SBATCH --partition=short-40core #SBATCH --nodes=1 #SBATCH --ntasks-per-node=40 #SBATCH --time=02:00:00 # hh:mm:ss # --- Optional: email when it ends or fails --- #SBATCH --mail-type=END,FAIL #SBATCH --mail-user=<you>@stonybrook.edu # --- Environment setup --- module purge module load intel/oneAPI/2022.2 module load compiler/latest module load mpi/latest export OMP_NUM_THREADS=1 echo "Job $SLURM_JOB_ID on $SLURM_JOB_NODELIST, $SLURM_NTASKS tasks, started $(date)" # --- The work --- cd $SLURM_SUBMIT_DIR mpirun ./my_app input.dat > computation.log echo "Finished $(date)"
Submit it and check on it:
sbatch my_job.slurm squeue -u $USER
Ready-made scripts for serial, multi-threaded, MPI, GPU, and array jobs are in Example jobs.
Asking for the right resources
- Pick the queue first. The queue decides the node type and the maximum run time. See the queue selection guide.
- Whole node or part of one? Queues without
-sharedgive you whole nodes, with all their memory. For small jobs, use a shared queue and set--mem. - Tasks vs. CPUs per task. Use
--ntasksfor MPI processes and--cpus-per-taskfor threads (OpenMP, Python multiprocessing). MatchOMP_NUM_THREADSto$SLURM_CPUS_PER_TASK. - Time. Ask for a realistic limit with some margin. Shorter requests often start sooner; if the job runs past its limit, Slurm stops it.
- Check afterward.
seff <jobid>shows how much CPU and memory you really used, so you can ask for less next time.
Directive reference
| Directive | What it sets | Example |
|---|---|---|
-p, --partition | Queue | #SBATCH -p short-40core |
-N, --nodes | Number of nodes | #SBATCH -N 2 |
-n, --ntasks | Total tasks (e.g. MPI ranks) | #SBATCH -n 80 |
--ntasks-per-node | Tasks on each node | #SBATCH --ntasks-per-node=40 |
-c, --cpus-per-task | CPUs for each task (threads) | #SBATCH -c 8 |
--mem | Memory per node | #SBATCH --mem=64GB |
--mem-per-cpu | Memory per CPU | #SBATCH --mem-per-cpu=2GB |
-t, --time | Time limit | #SBATCH -t 02:30:00 |
-J, --job-name | Job name | #SBATCH -J my_job |
-o, --output | File for normal output | #SBATCH -o job_%j.out |
-e, --error | File for error output | #SBATCH -e job_%j.err |
--gres | GPUs and other resources | #SBATCH --gres=gpu:2 |
--array | Job array indices | #SBATCH --array=1-100 |
--mail-type, --mail-user | Email notices | #SBATCH --mail-type=END,FAIL |
Useful variables inside a job
| Variable | Holds |
|---|---|
$SLURM_JOB_ID | The job ID |
$SLURM_SUBMIT_DIR | The folder you ran sbatch from |
$SLURM_JOB_NODELIST | The nodes the job is running on |
$SLURM_NTASKS | Total number of tasks |
$SLURM_CPUS_PER_TASK | CPUs given to each task |
$SLURM_ARRAY_TASK_ID | This task's index in a job array |
Run jobs in order (dependencies)
For work in steps, such as preprocessing, then analysis, then plotting, you can submit every step at once and have each one wait for the one before it. Slurm holds the later jobs until their condition is met.
# Submit the first step and keep its job ID jid=$(sbatch --parsable step1.slurm) # Start step 2 only if step 1 finishes successfully sbatch --dependency=afterok:$jid step2.slurm
| Condition | The new job starts once the earlier job has |
|---|---|
afterok:<jobid> | finished successfully (exit code 0) |
afternotok:<jobid> | failed, which is handy for a cleanup or alert step |
afterany:<jobid> | ended, whatever the outcome |
after:<jobid> | started running |
You can wait on several jobs at once, as in afterok:1234:1235. If a condition can never be met (step 1 failed and step 2 needed afterok), the waiting job stays in the queue with the reason DependencyNeverSatisfied. Cancel it with scancel <jobid>.
Make scripts safer and easier to debug
# Stop at the first error instead of carrying on set -e # Check the input exists before doing any work if [ ! -f "input.dat" ]; then echo "ERROR: input.dat not found" exit 1 fi # Time the main step start=$(date +%s) mpirun ./my_app input.dat echo "Computation took $(( $(date +%s) - start )) seconds"
- Start with
module purgeso modules left over from your login session don't interfere. - Load the same modules you compiled with.
- Test small first: a short run in
debug-40core, or an interactive session, before a big submission. - Keep a template for each kind of job you run often.
Troubleshooting
"sbatch: command not found"
Run module load slurm first.
"Batch job submission failed: Requested node configuration is not available"
You asked for more cores, memory, or GPUs than a node in that queue has, or used a queue that isn't reachable from your login node. Compare your request with the queue tables, and see which login node reaches which queues.
My job ended early with "TIME LIMIT" or "DUE TO TIME LIMIT"
It ran past its --time. Ask for more time, move to a longer queue, or save progress (checkpoint) so you can restart.
"Out of memory" or "oom-kill"
The job used more memory than it asked for. Raise --mem (on shared queues) or use more nodes. seff <jobid> shows the peak memory used.
Windows line endings: "/bin/bash^M: bad interpreter"
The script was saved on Windows. Convert it on the cluster with:
sed -i 's/\r$//' my_job.slurm
More commands for watching and changing jobs are in Managing jobs and the cheat sheet.