更新:
一些背景:
zsh
$LINENO
在函数内部调用时返回函数内部的行号。我需要一种方法来获取文件中的行号,并区分何时zsh
给我文件行号和函数行号。
我找不到zsh
环境变量来更改此行为以匹配其他 Bourne shell(例如bash
始终给出文件行号),因此我试图查看是否可以创建一个具有逻辑的函数,该函数始终可以输出文件行号的上下文。这就是我试图确定函数长度的原因。
$LINENO
如果有人知道在所有上下文中获取文件行号的好方法zsh
,我将不胜感激!
问题:
我搜索过这和这,但似乎找不到答案。是否有一种可移植的方法来编写函数定义的行数?(请参阅上面的“一些背景”。)
我最初的想法是捕获函数内容并将其通过管道传输到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?"
我最初的尝试是用 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}"
但是,在 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
有谁知道解决方案吗?谢谢你!
答案1
没有可移植的方法来检索 shell 函数的内容。有些贝壳有,有些则没有。流行的外壳短跑除了评估函数体之外,无法对函数体执行任何操作。
dash/src $ grep -F ndefun.body *.c
eval.c: evaltree(func->n.ndefun.body, flags & EV_TESTED);
parser.c: n->ndefun.body = command();
对源代码的进一步检查表明,不存在包含函数“长度”的单独数据结构,无论这意味着什么。
在确实有办法打印函数定义的 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
}