我们如何递归扩展函数内部的内联函数和别名?

我们如何递归扩展函数内部的内联函数和别名?

鸭子类型的嵌套问题:

function f1 { echo $1; } #with argument
function f2 { N=$((0+1)); f$N "fff"; } #with dynamic name

期望的结果:

function f2 { { echo $1; } "fff"; } 

注意。抱歉,我修改了问题,真正的编码问题。

如何解决问题?

答案1

这不是 bash 所做的事情。这也不是。所以,我真的很想知道你在这里想做什么。

类似 Bourne 的 shell 的工作方式是通过一个可调用函数表,该表实际上仅在调用时才会展开。因此,在被解释时f1;,函数f1得到“被称为,”而不是像宏那样更早。

因此,你的期望的结果与您上面发布的代码关系不大,并且本质上并不等效。函数有自己的上下文和符号,这些符号除了是一个{…}有作用域的语句集合之外还很重要。

因此,如果不改变bash和 consorts 的工作方式,您想要的东西是不可能的 - 此时,您正在使用不同的编程语言,更类似于 TeX 而不是 shell 脚本。 (顺便说一句,TeX 作为一种语言是……原创的,但在好的方面并不是占主导地位。)

所以,正如你的问题所述,你实际上想要改变您的程序无法像以前一样工作,这涉及到调用时在函数列表中进行符号查找f1;。这可能(并且将会)破坏一些利用重新定义函数能力的更复杂的脚本。

我觉得这不是一个好主意,但这是你的选择。你需要写一个静止的bash 脚本的解析器,即可以理解 shell 语法的解析器没有执行程序。原则上,可悲的是,

POSIX shell 语言在多个层面上挑战了编译器构造的传统智慧: shell 语言不是为静态解析而设计的,而是考虑到语法分析和扩展执行的交织。

特别是,我在这里强调:

词法分析取决于解析上下文和评估背景,

(Y. Régis-Gianas、N. Jeannerod、R. Treinen:Morbig:POSIX Shell 的静态解析器

这意味着,一般来说,您不能静态展开f1.您需要知道执行f1f2发生了什么!

POSIX shell 的设计不是作为静态语言(没有类似一致类型系统的东西)不能对此做出任何保证。它需要一个包含 an 的条件alias f1=f3来更改程序在运行时的内容! (还有许多其他机制可以用来解决这个问题。)换句话说,您唯一真正知道真正“含义”的时间f1f2f2执行时的每个点,并且您需要知道 shell 的完整状态(及其环境)。

因此,要做自己想做的事,你需要成为外壳;您需要修改 bash 并添加允许您打印(保存或记录)特定内容的扩展的功能,也许可以通过挂钩。

但也许你想要的比你在问题中要求的要小得多。也许您不想修改您的 shell 脚本,但只是想在您的 shell 脚本中随时打印函数的定义?这可以通过declare,即 来完成declare -fp f1

答案2

这就是你所追求的吗?

我确实对规格做了一些调整。与命令的第二个参数对应的函数作为函数 fout 加载到环境中。如果您运行脚本

. duck.sh <string> <function number> 

该函数被加载到父 shell 的环境中。输出显示所选的函数,以及基于第一个参数(如果有)的输出。

文件duck.sh:

#!/bin/bash

function f1 { echo $1; } #with argument
function f2 { f1; echo "here2 "$1; }
function f3 { f1; f2; echo "The Third "$1; }

function expandInner {
    while [[ $toExpand != "" ]];  do
        while read -r line; do
            getInner $line
        done <<< $toExpand
        toExpand=$(grep -w -o 'f[0-9]' <<< $inner)
    done
}

function getInner {

    tmpString=$(typeset -f $1)
    tmpString=$(echo $tmpString | awk 'BEGIN{RS="}"; FS="{"} {print $2}')
    inner=${inner/${line}/${tmpString}}

}

if [ -z "$2" ] ; then
    N=$((0+1))
else
    N=$2
fi

inner=$(echo $(typeset -f f$N) | awk 'BEGIN{RS="}"; FS="{"} {print $2}')
toExpand=$(grep -w -o 'f[0-9]' <<< $inner)
expandInner
echo "function fout { $inner ; echo \"fff\"; }" | tee ~/.tmp; source ~/.tmp; rm ~/.tmp
fout $1

相关内容