shell 脚本中的匿名函数

发布于 2024-12-19 22:37:51 字数 75 浏览 0 评论 0原文

是否可以创建类似于匿名函数的东西,其值可以分配给数组元素并稍后调用?我似乎找不到在 bash 脚本中执行此操作的方法,但也许有解决方法。

Is it possible to create something analogous to an anonymous function whose value can be assigned to an array element and later called? I can't seem to find a way to do this in a bash script but perhaps there's a workaround.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

黒涩兲箜 2024-12-26 22:37:51

简短回答:不。

详细回答:不。

完整答案:bash 中的函数不是一流对象,因此 bash 中不可能存在匿名函数之类的东西。

Short answer: No.

Long answer: Nooooooooooooo.

Complete answer: Functions in bash are not first-class objects, therefore there can be no such thing as an anonymous function in bash.

拥抱没勇气 2024-12-26 22:37:51

这是可能的;我写了一个库来完成这个任务,尽管这是一个非常奇怪的项目。源代码位于 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 该文件,然后返回其名称。这会导致杂散文件累积,这就是为什么该库还实现了异步标记/清除垃圾收集器。

It is possible; I wrote a library to do exactly this, though it's a very strange project. The source code is available at http://github.com/spencertipping/bash-lambda. Using this library:

$ 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
$

The trick is to have the fn function create a file containing the body of the function, chmod +x that file, then return its name. This causes stray files to accumulate, which is why the library also implements an asynchronous mark/sweep garbage collector.

友谊不毕业 2024-12-26 22:37:51

常见的技术是有条件地分配函数定义:

#!/bin/sh

case $1 in
a) foo() { echo case a; };;
b) foo() { echo case b; };;
*) foo() { echo default; } ;;
esac

foo

The common technique is to assign function definitions conditionally:

#!/bin/sh

case $1 in
a) foo() { echo case a; };;
b) foo() { echo case b; };;
*) foo() { echo default; } ;;
esac

foo
枯叶蝶 2024-12-26 22:37:51

如果您确实需要数组来存储函数,您可以定义命名函数并仅存储它们的名称。然后您可以将函数调用为 ${array[n]}。或者,您可以将它们命名为 func1 .. funcN,然后调用 func$n

If you really need array to store the functions, you can define named functions and store just their names. You can then call the function as ${array[n]}. Or, you can name them func1 .. funcN and then just call func$n.

胡大本事 2024-12-26 22:37:51

bash 是图灵完整的,所以这是完全可能的;)

但除此之外,它并不真正值得考虑。

你可以用类似的方法来模拟这种行为:

echo myval ; ( foocmd "$_" && barcmd "$_" )

但是为什么?!?

well bash is turing complete, soo thats perfectly possible ;)

but aside from this its not really worth the consideration.

you could simulate such behaviour though with something along this line:

echo myval ; ( foocmd "$_" && barcmd "$_" )

but why?!?

浊酒尽余欢 2024-12-26 22:37:51

我遇到这个问题是因为我正在寻找如何做类似的事情

[1,2,3,4,5].map(x => x*2).filter(x => x < 7);

,即能够以灵活的方式操纵管道中的先前结果。


xargs

我听说过在命令行上处理此问题的一个好方法是通过 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

默认情况下它将标准输入通过任何空格分割成单独的参数,然后将这些参数提供给命令(下面的示例会更清楚)

我刚刚了解到来自这非常有帮助gist Brainiarc7 写了 xargs 如何变得真正灵活和有用。 一定要阅读/浏览一下,它有更多解释,真的很好。我在下面提供了示例和我从中收集到的内容,希望对您有所帮助。

1. -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 可能非常有用

2. -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),但 % 是常规的。

3. -0:通过空字符(UTF+0000)对args进行分块

这不太方便,但是您可以通过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

4. -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/

I came across this question because I was looking for how to do something analogous to

[1,2,3,4,5].map(x => x*2).filter(x => x < 7);

i.e. Being able to manipulate previous results in a pipeline in a flexible way.


xargs

A nice way I had heard of to handle this on the command line is through the xargs command. My first impression was it wasn't very flexible

$ 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

By default it splits standard input by any whitespace into separate arguments, then feeds those arguments to the command (it'll be clearer with the examples below)

I just learned from this extremely helpful gist Brainiarc7 wrote how xargs can be really flexible and useful. Definitely read/skim that, it's really good with more explanation. I included examples and things I gleaned from it below though, hopefully it's helpful.

1. -n: Split up args into n-sized chunks

# Chunk args into groups of two
$ printf "one two\nthree\tfour" | xargs -n 2 echo "args> "
# =>
# args>  one two
# args>  three four

Using -n 1 will probably be very useful

2. -I: Interpolate args into a command using a placeholder

An example probably best illustrates how this one works.

# 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

You give -I the string you want to use as a placeholder. The placeholder can be whatever text you like (e.g. my_unique_placeholder), but % is conventional.

3. -0: Chunk args by the null character (UTF+0000)

This isn't as convenient, but you can use it to split by an arbitrary character via 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

4. -L: split args on n lines into a chunk

# 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/

鱼窥荷 2024-12-26 22:37:51

在您的 PATH 中创建 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" 

Create the fn file in your PATH

#!/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"

You can then do :

foo=$(fn 'echo $1')
${foo} "bar" 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文