用xargs调用shell函数


168

我正在尝试使用xargs并行调用一个更复杂的函数。

#!/bin/bash
echo_var(){
    echo $1
    return 0
}
seq -f "n%04g" 1 100 |xargs -n 1 -P 10 -i echo_var {} 
exit 0

这将返回错误

xargs: echo_var: No such file or directory

任何有关如何使用xargs来完成此操作的想法,或者任何其他解决方案都将受到欢迎。


2
user1148366危险,危险!不要使用bash进行并行编程-您会遇到很多问题。使用C / C ++和pthreads或Java线程,或任何使您对自己的工作进行漫长而费力思考的事情,因为并行编程需要很多思想才能正确。
David Souther 2012年

27
@DavidSouther如果任务是独立的,例如将所有这些图片文件转换为png,请不要担心。只有当您拥有同步(超出了等待所有时间)和通信时,它才会变得混乱。
ctrl-alt-delor 2014年

@DavidSouther-我是Java开发人员很长时间了,最​​近我一直在从事常规工作。我继续告诉人们:朋友不要让朋友写bash脚本。但是,我发现自己正在查看此帖子/解决方案,因为(悲伤的表情:()我正在bash中从事并行处理。我可以很容易地在groovy / java中进行它。糟糕!
Christian Bongiorno

Answers:


172

导出功能应该做到这一点(未测试):

export -f echo_var
seq -f "n%04g" 1 100 | xargs -n 1 -P 10 -I {} bash -c 'echo_var "$@"' _ {}

您可以使用内置函数printf而不是外部函数seq

printf "n%04g\n" {1..100} | xargs -n 1 -P 10 -I {} bash -c 'echo_var "$@"' _ {}

同样,使用return 0exit 0这样将掩盖其前面的命令可能产生的任何错误值。另外,如果没有错误,则为默认设置,因此有些多余。

@phobic提到bash命令可以被简化为

bash -c 'echo_var "{}"'

{}直接将其移入其中。但这容易受到@Sasha指出的命令注入的影响。

这是为什么不应该使用嵌入式格式的示例:

$ echo '$(date)' | xargs -I {} bash -c 'echo_var "{}"'
Sun Aug 18 11:56:45 CDT 2019

另一个例子,为什么不

echo '\"; date\"' | xargs -I {} bash -c 'echo_var "{}"'

这是使用安全格式输出的内容

$ echo '$(date)' | xargs -I {} bash -c 'echo_var "$@"' _ {}
$(date)

这相当于使用参数化 SQL 查询来避免注入

我在这里使用date的是命令替换或转义引号,而不是rmSasha注释中使用的命令,因为它是非破坏性的。


14
再讨论一下:xargs执行一个名为process的全新实例。在这种情况下,请提供名称echo_var,它是此脚本中的函数,而不是PATH中的进程(程序)。Dennis解决方案的作用是导出供bb子进程使用的功能,然后派生到子进程并在其中执行。
David Souther 2012年

7
是什么的意义_\,没有他们,这是不是为我工作
Hashbrown

9
@Hashbrown:下划线(_)提供了一个占位符argv[0]$0)和几乎所有的东西可以在那里使用。我想我添加了反斜线分号(\;),因为它用于终止中的-exec子句find,但是在这里没有它的情况下它对我有用。实际上,如果使用该函数$@代替,$1则它将分号视为参数,因此应将其省略。
暂停,直到另行通知。

4
xargs的-i参数已被弃用。使用-I(大写i)代替。
Nicolai S

11
您可以通过在bash的命令字符串中包含xargs的参数来简化此过程bash -c 'echo_var "{}"'。因此,您不需要最后的_ {}。
pho16年

16

使用GNU Parallel看起来像这样:

#!/bin/bash
echo_var(){
    echo $1
    return 0
}
export -f echo_var
seq -f "n%04g" 1 100 | parallel -P 10 echo_var {} 
exit 0

如果您使用版本20170822,则甚至export -f不必运行以下命令:

. `which env_parallel.bash`
seq -f "n%04g" 1 100 | env_parallel -P 10 echo_var {} 

我在哪里可以买到osx?
尼克

nvm是zsh中的setopt
尼克,

在错误Ole中得到此信息sh: parallel_bash_environment: line 67: unexpected EOF while looking for matching ''sh:parallel_bash_environment:第79行:语法错误:文件意外结束sh:导入针对parallel_bash_environment' /usr/local/bin/bash: parallel_bash_environment: line 67: unexpected EOF while looking for matching / usr / local / bin / bash的函数定义的错误:parallel_bash_environment:第79行:语法错误:意外结束文件/ usr / local / bin / bash:导入`...的函数定义时出错
尼克

您已经被shellaftershocked了:Shellshock并没有直接影响GNU Parallel。但是,解决shellshock的方法是:彻底破坏了--env和env_parallel技巧。据信它已在git版本中修复:git.savannah.gnu.org/cgit/parallel.git/snapshot/…–
Ole Tange

1
我喜欢这个答案,因为它让我发现了并行工具
JR Utily 2015年

10

这样的事情也应该起作用:

function testing() { sleep $1 ; }
echo {1..10} | xargs -n 1 | xargs -I@ -P4 bash -c "$(declare -f testing) ; testing @ ; echo @ "

1

也许这不是一个好习惯,但是如果您要在.bashrc或其他脚本中定义函数,则可以使用以下设置包装文件或至少包裹函数定义allexport

set -o allexport

function funcy_town {
  echo 'this is a function'
}
function func_rock {
  echo 'this is a function, but different'
}
function cyber_func {
  echo 'this function does important things'
}
function the_man_from_funcle {
  echo 'not gonna lie'
}
function funcle_wiggly {
  echo 'at this point I\'m doing it for the funny names'
}
function extreme_function {
  echo 'goodbye'
}

set +o allexport
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.