使用xargs -P时如何将代码提取到函数中?

问题描述

在第一时间,我已经编写了代码,并且运行良好。

# version1
all_num=10
thread_num=5 
a=$(date +%H%M%s) 
seq 1 ${all_num} | xargs -n 1 -I {} -P ${thread_num} sh -c 'echo abc{}' 
b=$(date +%H%M%s) 
echo -e "startTime:\t$a"
echo -e "endTime:\t$b"

现在我想将代码提取一个函数中,但这是错误的,如何解决

get_file(i){
echo "abc"+i
 } 
all_num=10
thread_num=5 
a=$(date +%H%M%s) 
seq 1 ${all_num} | xargs -n 1 -I {} -P ${thread_num} sh -c "$(get_file {})"
b=$(date +%H%M%s) 
echo -e "startTime:\t$a"
echo -e "endTime:\t$b"

解决方法

因为不能保证/bin/sh支持 打印在评估时定义您的函数的文本,或者通过环境导出函数,所以我们需要用困难的方式做到这一点,只是在xargs开始的sh副本中复制函数的文本。

此站点中已经存在其他问题,描述了如何使用bash来完成此任务,这相当容易。见f / e How can I use xargs to run a function in a command substitution for each match?

#!/bin/sh

all_num=10
thread_num=5 
batch_size=1  # but with a larger all_num,turn this up to start fewer copies of sh

a=$(date +%H%M%S) # warning: this is really inefficient
seq 1 ${all_num} | xargs -n "${batch_size}" -P "${thread_num}" sh -c '
  get_file() { i=$1; echo "abc ${i}"; }
  for arg do
    get_file "$arg"
  done
' _
b=$(date +%H%M%S)

printf 'startTime:\t%s\n' "$a"
printf 'endTime:\t%s\n' "$b"

注意:

  • echo -e不保证可以与/bin/sh一起使用。而且,要使外壳真正兼容,需要echo -e-e写入其输出。请参阅Why is printf better than echo?上的UNIX & Linux Stack Exchangethe POSIX echo specification的APPLICATION USAGE部分。
  • {}放在sh -c '...{}...'的位置确实是个坏主意。考虑传递给您的文件名包含$(rm -rf ~)'$(rm -rf ~)'的情况-无法将其安全地插入未加引号的上下文带双引号的上下文单引号上下文,或者 Heredoc。
  • 请注意,seq也是非标准的,不能保证在所有符合POSIX的系统上都存在。 i=0; while [ "$i" -lt "$all_num" ]; do echo "$i"; i=$((i + 1)); done是可以在所有POSIX系统上使用的替代方法。