简体   繁体   English

Shell 脚本 - 批量循环

[英]Shell script - loop in batches

I have a sample script like below, where I pass the server names as comma separated stings and execute the functions for each server.我有一个如下所示的示例脚本,我在其中将服务器名称作为逗号分隔字符串传递,并为每个服务器执行函数。 Now I need to execute this in batches, eg in first batch functions will call with a,b,c,d.现在我需要分批执行它,例如,在第一批函数中将调用 a、b、c、d。 Once finished they will take next 4 and call the functions and at last they will call last 2. I can't change the 'servers' variable.完成后,他们将使用下一个 4 并调用函数,最后他们将调用最后 2 个。我无法更改“服务器”变量。 Any ides/suggestions.任何想法/建议。

servers = a,b,c,d,e,f,g,h,i,j
OIFS=$IFS;
IFS=",";
for server in ${servers}
do
 function1 server
done
for server in ${servers}
do
 function2 server
done
for server in ${servers}
do
 function3 server
done
IFS=$OIFS;

Please note that server variable length is not fixed and based on the environment it loads different servers.请注意,服务器变量长度不是固定的,它会根据加载不同服务器的环境而定。

Read the server list into an array, then use substring expansion (aka "slicing").将服务器列表读入数组,然后使用子字符串扩展(也称为“切片”)。 You can also store the names of the functions to call in an array, if I (now) understand your concern over the size of the list of servers.如果我(现在)理解您对服务器列表大小的担忧,您还可以将要调用的函数的名称存储在数组中。

IFS=, read -a s <<< "$servers"

bs=4  # batch size
for ((i=0; i<=${#s[@]}; i+=bs)); do
    function1 "${s[@]:i:bs}"
    function2 "${s[@]:i:bs}"
    function3 "${s[@]:i:bs}"
done

Looks like a job for GNU Parallel to me.对我来说,这看起来像是GNU Parallel的工作。 Something like this:像这样:

parallel -d ',' -k -j 4 'func1 {1}; func2 {1}; func3 {1}'  <<< $servers

Try it out like this:试试这样:

parallel -d ',' -k -j 4 'echo {1}; sleep 2'  <<< $servers
a
b
c
d
e
f
g
h
i
j

If they really are functions (rather than shell scripts or executables), remember to export them like this:如果它们确实是函数(而不是 shell 脚本或可执行文件),请记住像这样导出它们:

func1() {
  echo Doing it for $1
  sleep 2
  echo Done with $1
}

export -f func1

Update Inspired by @chepner answer, i've modified the loop to make it dynamic also in the call of the functions.更新@chepner回答的启发,我修改了循环以使其在函数调用中也动态化。

function1 () { echo "f1: $@"; }
function2 () { echo "f2: $@"; }
function3 () { echo "f3: $@"; }

servers=a,b,c,d,e,f,g,h,i,j
slice=4

IFS=, read -r -a array <<< "${servers}"

for index in "${!array[@]}"
do
    let "n = (index / slice) + 1" # n = 1 in (0..3), 2 in (4..7), 3 in (8..11), ...
    function${n} ${array[i]}
done

Output输出

f1: a f1: 一个
f1: b f1: 乙
f1: c f1: c
f1: d f1:d
f2: e f2: 电子
f2: f f2: f
f2: g f2: 克
f2: h f2: 小时
f3: i F3:我
f3: j f3: j

Obviously this works with a caveat: the functions have to be called function1, function2, ... (actually the functions' name can be remapped too, loosing a bit of dynamism).显然,这有一个警告:函数必须被称为function1, function2, ... (实际上函数的名称也可以重新映射,失去一点活力)。

Otherwise a more classic static loop:否则更经典的静态循环:

for index in "${!array[@]}"; do
    let "n = (index / slice) + 1"
    ((n == 1)) && function1 ${array[index]}
    ((n == 2)) && function2 ${array[index]}
    ((n == 3)) && function3 ${array[index]}
done

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM