使用 zsh 或 bash,我想运行一个脚本,该脚本可能会提示用户输入多个命令并将它们存储为函数,但是我发现eval "function $FNCNAME() {"
或echo "function $FNCNAME() {" | zsh -is
除非直接键入否则无效,因为脚本不会在执行之前等待更多输入继续下一行或退出。
如何在接受用户输入的同时阻止脚本进程,并仅在用户使用final(不带引号)结束函数定义时才继续}
?
要求是:
- shell 自己的上下文感知自动完成功能处于活动状态。
- 脚本不应立即执行延迟的命令,但应能够调用或打印新函数的定义
这个问题仅限于一般的管道和交互问题。我不是要求:
- 如何以任何方式向脚本提供预先编写的命令。
- 如何提供“最佳的用户体验”或者如何改进它。
- 为什么我不应该解决这个问题而做别的事情。
答案1
在 中zsh
,它可能是这样的:
make-function() {
local psvar=$1
local line= body=
print -ru2 Please enter the definition of the $psvar function, one line at a time, terminate with an empty line.
while
line=
vared -p '%v> ' line
[[ -n $line ]]
do
body+=$line$'\n'
done
functions[$psvar]=$body
}
那么例如:
$ make-function f
Please enter the definition of the f function, one line at a time, terminate with an empty line.
f> echo test
f> return 42
f>
$ f
test
$ echo $?
42
$ functions f
f () {
echo test
return 42
}
你也可以这样做:
vared 'functions[f]'
f
在行编辑器中编辑函数体。请注意,Enter离开编辑器后,您需要Alt+Enter或Esc后跟Enter(或Ctrl+ v, Ctrl+j就像 bash 的 readline 中一样)以像往常一样在函数体中输入文字换行符。
vared
(变量编辑器)是一个内置函数,它调用 zsh 行编辑器(zle)来编辑变量的内容,$functions
是一个特殊的关联数组,它将函数名称映射到其主体中代码的表示形式。
在 中bash
,您可以通过使用IFS= read -rep "$psvar> " line
where -e
using readline to edit来执行一些接近的操作$line
,并且您可以使用eval "$psvar() { $body; }"
名称和主体来创建函数。
答案2
这就是你想做的吗?
$ cat ./tst.sh
#!/usr/bin/env bash
tmp=$(mktemp) || exit 1
trap 'rm -f "$tmp"; exit' EXIT
fncname='foo'
printf 'List commands, terminated with Control-D\n' >&2
{
printf '%s () {\n' "$fncname"
while IFS= read -r line; do
printf '\t%s\n' "$line"
done
printf '}\n'
} > "$tmp" &&
. "$tmp"
declare -f "$fncname"
"$fncname"
$ ./tst.sh
List commands, terminated with Control-D
echo 'hello'
date
echo 'world'
<- I hit Control-D here
foo ()
{
echo 'hello';
date;
echo 'world'
}
hello
Wed Jan 3 15:48:38 CST 2024
world