0

Suppose I have two space-delimited strings in my bash script, which are

permitted_hosts="node1 node2 node3"

and

runs_list="run1 run2 run3 run4 run5"

These respectively represent the list of permitted hosts and the list of runs to execute. So, I need to run each of the runs in $runs_list on 1 of the hosts in $permitted_hosts.

What I'd like to do is divide $runs_list into $N substrings, where $N is the number of elements in $permitted_hosts and where each of the $N substrings is mapped to a different element in $permitted_hosts.

If that's confusing, then consider this concrete workaround solution. For the exact given values of $permitted_hosts and $runs_list above, the following bash script checks the current host, and if the current host is in $permitted_hosts, then it launches the runs in $runs_list that are associated with the current host. Of course, this script doesn't use the variables $permitted_hosts and $runs_list, but it achieves the desired effect for the given example. What I'm really trying to do is modify the code below so that I can modify the values of variables $permitted_hosts and $runs_list and it will work appropriately.

#!/bin/bash
hostname=$(hostname)
if [ "$hostname" == "node1" ]; then
    runs="run1 run2"
elif [ "$hostname" == "node2" ]; then
    runs="run3 run4"
elif [ "$hostname" == "node3" ]; then
    runs="run5"
else
    echo "ERROR: Invoked on invalid host ('$hostname')! Aborting." 
    exit 0
fi

for run in $runs; do
    ./launch $run
done

1 Answer 1

1

So, firstly — instead of space-delimited strings, you should probably use arrays:

permitted_hosts=(node1 node2 node3)
runs_list=(run1 run2 run3 run4 run5)

If you have to start out with space-delimited strings, you can at least convert them to arrays:

permitted_hosts=($permitted_hosts_str)
runs_list=($runs_list_str)

That out of the way . . . basically you have two steps: (1) convert the hostname into an integer representing its position in permitted_hosts:

hostname="$(hostname)"
num_hosts="${#permitted_hosts[@]}"      # for convenience

host_index=0
while true ; do
    if [[ "${permitted_hosts[host_index]}" = "$hostname" ]] ; then
        break
    fi
    (( ++host_index ))
    if (( host_index > num_hosts )) ; then
        printf 'ERROR: Invoked on invalid host ('%s')! Aborting.\n' "$hostname" >&2
        exit 1
    fi
done
# host_index is now an integer index into permitted_hosts

and (2) convert this integer into an appropriate subset of runs_list:

num_runs="${#runs_list[@]}"      # for convenience
for (( run_index = host_index ; run_index < num_runs ; run_index += num_hosts )) ; do
    ./launch "${runs_list[run_index]}"
done

So, for example, if you have H hosts, then host #0 will launch run #0, run #H, run #2H, etc.; host #1 will launch run #1, run #H+1, run #2H+1, etc.; and so on.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks a lot. I knew there had to be a better way :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.