テキストの行を読み、編集中にカーソルを左右に移動できるようにします。
cat
を呼び出すか、bashでread
を使用し、矢印キーを押すと、カーソルを移動する代わりに^[[A^[[B^[[C^[[D
を取得します。
gnome-terminal
およびmate-terminal
のbash
をローカルで使用します(SSHなし)。
@ steeldriverのおかげで、カーソルを左右に移動でき、上下矢印を押してもbash履歴が表示されないソリューションが見つかりました。
history -c # clear history
read -ep "$*" var # read value using readline,
# display Prompt supplied as argument
echo "$var" # echo the value so it can be captured by the caller
次に、別のスクリプトまたはシェルからこのスクリプトを呼び出します。
var=`readline 'value: '`
この関数はサブシェルで実行するように定義でき、上記のスクリプトと本質的に同じになります。
readline() (
history -c
read -ep "$*" var
echo "$var"
)
または、現在のシェルで直接実行することもできます。その場合、現在のシェルの履歴をクリアする前に保存し、復元する必要があります。
readline() {
history -w # write current history to the $HISTFILE
history -c # ...
read -ep "$*" var # ... same as above
echo "$var" # ...
history -r # resotre history (read from $HISTFILE)
}
ただし、を押すことにした場合 Ctrl+C テキストを入力している間、履歴が復元される前に機能が中断されるため、履歴が表示されなくなります。
解決策は、トラップを使用することです。 INTシグナルにトラップを設定して、履歴を復元し、シグナルを「トラップ解除」します。
readline() {
# set up a trap which restores history and removes itself
trap "history -r; trap - SIGINT; return" SIGINT
history -w
history -c
read -ep "$*" var
echo "$var"
history -r
trap - SIGINT
}
ただし、INTシグナルにトラップが既に設定されている場合は、単に破棄します。したがって、既存のトラップを保存してから、新しいトラップを設定し、ビジネスを行ってから古いトラップを復元する必要があります。
readline() {
local err=0 sigint_trap orig_trap
sigint_trap=`trap -p | grep ' SIGINT$'`
if [[ $sigint_trap ]]; then
# A trap was already set up ‒ save it
orig_trap=`sed 's/trap -- \(.*\) SIGINT$/\1/' <<<"$sigint_trap"`
fi
# Don't do anything upon receiving SIGINT (eg. user pressed Ctrl+C).
# This is to prevent the function from exiting before it has restored
# the original trap.
trap ':' SIGINT
# `read` must be called from a subshell, otherwise it will run
# again and again when interrupted. This has something to do with
# the fact that `read` is a Shell builtin. Since `read` reads a value
# into variable in a subshell, this variable won't exist in the parent
# Shell. And since a subshell is already used, the history might as well
# be cleared in the subshell instead of the current Shell ‒ then it's
# not necessary to save and restore it. If this subshell returns a
# non-zero value, the call to `read` was interrupted, and there will be
# no output. However, no output does not indicate an interrupted read,
# since the input could have been empty. That's why an exit code is
# necessary ‒ to determine whether the read was interrupted.
( history -c
read -ep "$*" var
echo "$var"
) || {
# `read` was interrupted ‒ save the exit code and echo a newline
# to stderr (because stdin is captured by the caller).
err=$?
echo >&2
}
# The subshell can be replaced by a call to the above script:
## "`which readline`" "$@" || { err=$?; echo >&2; }
if [[ $sigint_trap ]]; then
# Restore the old trap
trap "`eval echo "$orig_trap"`" SIGINT
else
# Remove trap
trap - SIGINT
fi
# Return non-zero if interrupted, else zero
return $err
}
したがって、この最後のバージョンは元のバージョンよりも「少し」複雑であり、サブシェルの起動を回避しませんが、読み取りが成功したかどうかの指標を提供します(どちらの単純なバージョンもそうではありません)。
次のように使用できます。
my_function() {
...
message=`readline $'\e[1mCommit message:\e[m '` || {
echo "[User abort]" >&2
return 1
}
...
}
read
シェルのbash
ビルトインでは、-e
オプションを使用してreadlineサポートを有効にできます。 help read
から:
-e use Readline to obtain the line in an interactive Shell
例えば
read -ep "Please enter some text: "
cat
ヒアドキュメントでこれを行う方法を知りません。