是否有可能创建类似于匿名函数的东西,其值可以分配给数组元素并稍后调用?我似乎找不到在bash脚本中实现这一点的方法,但也许有一些变通方法。
简短回答:不行。
长篇回答:不-行-啊-啊-啊-啊-啊-啊-啊-啊-啊。
完整回答:在Bash中,函数不是一等对象,因此无法存在匿名函数。
有可能做到,我写了一个库来实现这个功能,不过这是一个非常奇怪的项目。源代码可在http://github.com/spencertipping/bash-lambda上找到。使用这个库:
$ my_array=()
$ my_array[0]=$(fn x 'echo $((x + 1))')
$ my_array[1]=$(fn x 'echo $((x + 2))')
$ ${my_array[0]} 5
6
$ ${my_array[1]} 5
7
$
关键是让fn
函数创建一个文件,其中包含函数的主体,然后chmod +x
该文件,并返回其名称。这会导致杂散的文件积累,因此该库还实现了异步标记/清除垃圾回收器。
some_command; ${my_array[0]} 5
或者some_command && ${my_array[0]} 5
,两个表达式都只会在运行some_command
之后才会运行${my_array[0]} 5
。 - Nick Bull如果您真的需要使用数组来存储函数,您可以定义命名函数并仅存储它们的名称。然后,您可以调用函数如${array[n]}
。或者,您可以将它们命名为func1
.. funcN
,然后只需调用func$n
。
declare -n reference_name
功能,其名称可以抽象化,例如:declare -n aref; a() { echo "function a"; }; aref=a
,然后执行$aref
将会运行函数a
。 - Jack Waseyecho ${!aref}
,然后 ${!aref}
。 - Jack Wasey常见的技巧是有条件地分配函数定义:
#!/bin/sh
case $1 in a) foo() { echo case a; };; b) foo() { echo case b; };; *) foo() { echo default; } ;; esac
foo
嗯,Bash是图灵完备的,所以这是完全可能的;)
但除此之外,这并不值得考虑。
不过你可以用类似以下的方式模拟这种行为:
echo myval ; ( foocmd "$_" && barcmd "$_" )
但为什么?!?
[1,2,3,4,5].map(x => x*2).filter(x => x < 7);
即能够以灵活的方式操纵管道中的先前结果。
在命令行中处理这个问题的一种好方法是使用xargs
命令。我的第一印象是它不太灵活。
$ printf "one two\nthree\tfour" | xargs echo "args> "
# => args> one two three four
$ printf "one two three four" | xargs echo "args> "
# => args> one two three four
默认情况下,它将标准输入按任何空格分隔成单独的参数,然后将这些参数提供给命令(通过下面的示例会更清楚)
我刚学到了Brainiarc7编写的非常有用的Gist中xargs可以非常灵活和有用。 一定要阅读/浏览一下,它有更多的解释,非常好。 我在下面包含了示例和我从中获得的东西,希望对您有所帮助。
-n
:将参数拆分为n
个大小的块# Chunk args into groups of two
$ printf "one two\nthree\tfour" | xargs -n 2 echo "args> "
# =>
# args> one two
# args> three four
-n 1
可能非常有用。
-I
: 使用占位符将参数插入命令中一个例子可能最好地说明了这个功能的工作原理。
# Indicate we want `%` to be the placeholder, split args into groups of two,
# then interpolate them in the command at the placeholder
printf 'one two three four' | xargs -I % -n 2 echo "Chunk of args> " % " <in the middle of a command"
# =>
# Chunk of args> one two <in the middle of a command
# Chunk of args> three four <in the middle of a command
你需要给-I
传入一个字符串作为占位符。占位符可以是任意文本(例如my_unique_placeholder
),但%
是常规选择。
-0
:使用空字符(UTF+0000)对参数进行分块虽然不太方便,但是你可以使用它通过tr
来按任意字符拆分。
# Split arg chunks by tab character:
$ printf 'one two\tthree\tfour' | tr '\t' "\0" | xargs -0 -n 1 echo "args> "
# =>
# args> one two
# args> three
# args> four
-L
: 将参数在 n
行上拆分为一块# Take all args on every 2 lines as a chunk
$ printf 'one two\nthree\nfour' | xargs -L 2 echo "args> "
# =>
# args> one two three
# args> four
https://gist.github.com/Brainiarc7/133fd582e124981c08cbafca98455ee9 https://shapeshed.com/unix-xargs/
({arg}) => {body}
是正在发生的事情吗? - robrecord{}
类似于 manpage 的方式,但在 JavaScript 上下文中这是没有意义的!希望修改后更清晰明了。 - matt0089(arg) => body
这种实现方式正是我正在寻找的。修改很有道理。谢谢! - robrecordPATH
中创建fn文件。#!/bin/sh
printusage () {
printf "Create anonymous function, for example\n"
printf "fn 'echo "$1 $2"'"
exit 1
}
[ "$#" = "1" ] || printusage
fun=$1
[ "$fun" = "" ] && printusage
fun_file="$(mktemp /tmp/fun_XXXXXX)"
echo "#!/bin/sh" > "$fun_file"
echo "" >> "$fun_file"
echo "$fun" >> "$fun_file"
chmod u+x "$fun_file"
echo "$fun_file"
然后,您可以执行:
foo=$(fn 'echo $1')
${foo} "bar"
eval
。 - choroba