在 Shell 中获取函数的长度

A. *_*dry 2 shell sed awk

更新:

一些背景:

zsh在函数内部调用时返回函数内部的行号$LINENO。我需要一种方法来获取文件中的行号并区分何时zsh给我文件行号与函数行号。

我找不到一个zsh环境变量来改变这种行为以匹配其他 Bourne shell(例如bash总是给出文件行号),所以我试图看看我是否可以创建一个具有逻辑的函数,不管它总是输出文件行号的上下文。这就是为什么我试图确定函数的长度。

如果任何人的一个好办法知道与获取文件的行号$LINENOzsh所有环境中,我将不胜感激!


题:

我已经搜索了thisthis,但似乎找不到答案。是否有一种可移植的方法来编写函数定义的行数?(请参阅上面的“一些背景”。)

我最初的想法是捕获函数内容并将其通过管道传输到wc -l.

考虑以下测试文件:

测试文件:

#! /bin/sh
#
# test_file.sh

func1() { echo 'A one-liner'; }  # With a nasty comment at the end
func2 (){
  echo "A sneaky } included"
  # Or an actual code block
  {
    echo 'hi'
    echo 'there'
  }
}

func3() { echo "I'm on a line."; }; echo 'And so am I'

func4(){ echo "But I'm a \"stand-alone\" one-liner."; }

func5() {
  echo "I'm a nice function."
  echo "And you can too!"


}

echo "Can we do this?"
Run Code Online (Sandbox Code Playgroud)

我最初的尝试是将相应的 {} 对与 sed 匹配:

解决方案尝试:

#! /bin/sh
#
# function_length
#
# $1: string: absolute path to file
# $2: string: name of function (without ()'s)

fp=$(realpath "$1")
func_name="$2"

func_contents=$(cat "${fp}" |
  sed -E -n '
/'"${func_name}"' ?[(][)]/{
  :top
  /[}]/!{
    H
    d
  }
  /[}]/{
    x
    s/[{]//
    t next
    G
    b end
  }
  :next
  x
  b top
  :end
  p
  q
}')

echo "${func_contents}"
echo

func_len=$(echo "${func_contents}" | wc -l)

echo "Function Length: ${func_len}"
Run Code Online (Sandbox Code Playgroud)

但是,在 zsh 中运行它会给出

$ ./function_length ./test_file.sh func1      

func1() { echo 'A one-liner'; }  # With a nasty comment at the end

Function Length: 2
$ ./function_length ./test_file.sh func2


Function Length: 1
$ ./function_length ./test_file.sh func3

func3() { echo "I'm on a line."; }; echo 'And so am I'

Function Length: 2
$ ./function_length ./test_file.sh func4

func4(){ echo "But I'm a \"stand-alone\" one-liner."; }

Function Length: 2
$ ./function_length ./test_file.sh func5


Function Length: 1
Run Code Online (Sandbox Code Playgroud)

有谁知道解决方案?谢谢!

Gil*_*il' 8

没有可移植的方法来检索 shell 函数的内容。有些贝壳有一个,有些没有。流行的 shell破折号除了评估函数体之外,无法对函数体做任何事情。

dash/src $ grep -F ndefun.body *.c
eval.c: evaltree(func->n.ndefun.body, flags & EV_TESTED);
parser.c:                               n->ndefun.body = command();
Run Code Online (Sandbox Code Playgroud)

对源代码的进一步检查表明,没有包含函数“长度”的单独数据结构,无论这意味着什么。

在确实可以打印函数定义的 shell 中,它的格式可能与源代码不同。所以“长度”不是一个有意义的数字。

$ bash -c 'f () { echo hello; echo world; }; typeset -f f'
f () 
{ 
    echo hello;
    echo world
}
$ ksh -c 'f () { echo hello; echo world; }; typeset -f f'; echo
f() { echo hello; echo world; };
$ mksh -c 'f () { echo hello; echo world; }; typeset -f f'
f() {
        \echo hello 
        \echo world 
} 
$ zsh -c 'f () { echo hello; echo world; }; typeset -f f'
f () {
        echo hello
        echo world
}
Run Code Online (Sandbox Code Playgroud)