カスタム bash クライアント履歴の重複

カスタム bash クライアント履歴の重複

私は、ssh 経由で Zimbra サーバー上でさまざまなタスクを実行するクライアントを作成していますが、ちょっとした問題に遭遇しました。コードは次のとおりです。

#!/bin/bash
set -e
export PATH=/usr/bin:/bin:/usr/sbin:/sbin
export HISTCONTROL=ignoreboth

# History management
if [ -f $HOME/.zmcli_history ]; then
  history -r $HOME/.zmcli_history
else
  touch $HOME/.zmcli_history
  history -r $HOME/.zmcli_history
fi
trap "history -a $HOME/.zmcli_history && echo -e '\nExiting now.\n'" exit

# Styling
yellow='[33m'
bold='[1m'
off='[0m'

echo

# Client
while :; do
  read -ep "$bold${yellow}zimbra_cli[${off}server_domain$bold${yellow}]> $off" comm
  history -s "$comm"
done

注意: このスクリプトを実行すると、ホーム ディレクトリに履歴ファイル (.zmcli_history) が作成されます。

すべてが意図したとおりに動作し、履歴もすべてそこにありますが、履歴をスクロールし続けると、以前のコマンドの一部 (通常は長い) が残ることがよくあります。コマンドのその部分は、CTRL+L を押して画面をクリアし、通常の状態にリセットしない限り、セッションの残りの間プロンプトの一部として機能します。私は、bash ターミナルでこの問題を抱えている人々を助ける多くの投稿を読みました。彼らの問題は、PS1 が不適切にフォーマットされており、bash がプロンプト文字列の長さについて混乱していたというものでした。ここでも似たようなことかもしれませんが、それらの解決策は機能しません。なぜなら、read コマンドは echo のようにエスケープ文字 (\e) を使用できないからです。

リテラル エスケープ (vim 挿入モードで CTRL+V ESCAPE) を使用してカラー シーケンスをエスケープする方法を見つけました。色は機能しますが、この履歴の問題で行き詰まっています。

私が試したこと:

  • コマンド置換:: echo -e でカラーコードを出力できるように記述してエスケープし、それを読み取りコマンド $(echo -e '\e[33m') でエコーします。色はまだ表示されますが、履歴の問題には役立ちませんでした。
  • 色コードの前後にエスケープされた [ と ] を追加する
  • 読み取りコマンドの前にある別の echo コマンドに、色分けされたプロンプト全体を配置します。欠点は、読み取りコマンド (別の echo) の後まで書式設定をオフにできないことです。つまり、プロンプトとコマンド全体が太字で色付きになります。また、ここで CTRL+L を押すと、プロンプトもクリアされ、カーソルだけが残ります。

最後に、履歴を削除できないので、色を削除してみました。しかし、そうするとコマンドと出力を素早く区別できなくなります。

スクリプトを起動し、10 ~ 15 個の長い (意味不明な) コマンドを入力すると、問題を再現できます。その後、履歴を上下にスクロールしてみると、私が言っていることがわかるでしょう。

これを機能させる方法を誰か知っていますか?

答え1

あなたのスクリプト、そのまま、問題を再現できませんでした。色などを有効にした後でのみ、readlineが混乱し始めました。記録のために、私はこれらを有効にしました

# Styling
yellow=$'\e[33m'
bold=$'\e[1m'
off=$'\e[0m'

そしてそれは本当であり\[\]助けにならない彼らは、PS1

しかし、私はこの答え. そこには

開いてみるinfo readlineと、次のものがありました:

[…]
アプリケーションは、プロンプトに、表示時に物理的な画面スペースを占有しない文字が含まれていることを示すために、そのような文字のシーケンスを特殊なマーカー と RL_PROMPT_START_IGNORE(RL_PROMPT_END_IGNOREで宣言されています) で囲むreadline.hことができます。これを使用して、プロンプトに端末固有のエスケープ シーケンスを埋め込むことができます。

たとえば、テキストを検索しRL_PROMPT_START_IGNORERL_PROMPT_END_IGNORE定義するreadline.hと、次のものが見つかりました:

/* Definitions available for use by readline clients. */
#define RL_PROMPT_START_IGNORE  '\001'
#define RL_PROMPT_END_IGNORE    '\002'

このことから、私は次の結論に至りました。

# Styling
yellow=$'\1\e[33m\2'
bold=$'\1\e[1m\2'
off=$'\1\e[0m\2'

完璧に動作します。

関連情報