zshまたはbashを使用してユーザーに複数のコマンドを要求し、それを関数として保存できるスクリプトを実行したいが、スクリプトが続行する前に追加の入力を待たないため、直接入力しないと機能しないことがわかりeval "function $FNCNAME() {"
ました。echo "function $FNCNAME() {" | zsh -is
。次の行または終了。
ユーザー入力を受け付けている間にスクリプトプロセスをブロックし、ユーザーがfinal(引用符なし)で関数定義を終了したときにのみ続行するにはどうすればよいですか}
?
要件は次のとおりです。
- シェル自体のコンテキスト認識オートコンプリートが有効になっています。
- スクリプトは直ちに遅延コマンドを実行してはいけませんが、新しい関数の定義を呼び出すか印刷する必要があります。
この質問は、一般的な配管と相互作用の問題に限定されています。私は以下を要求しません:
- どのようにして事前に作成されたコマンドをスクリプトに提供するにはどうすればよいですか?
- 「最高のユーザーエクスペリエンス」を提供する方法、またはそれを改善する方法。
- なぜこの問題を解決して他のことをしないのですか?
答え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(またはbashのreadlineのようにCtrl+ v、Ctrl+)が必要です。j
vared
(変数エディタ)は、zsh行エディタ(zle)を呼び出して変数の内容を編集する組み込み関数で、関数名をその本体のコード$functions
表現にマッピングする特別な連想配列です。
では、readlineを使用して編集するwhereを使用して同様の操作を実行でき、bash
名前と本文を使用して関数を生成できます。IFS= read -rep "$psvar> " line
-e
$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