web-dev-qa-db-ja.com

端末の最後の行を上書きする

私のbashスクリプトは次のように見えます:

echo "Description:"
while [ $finishInput -eq 0 ]; do
read tmp
desc="$desc"$'\n'"$tmp"
if [ -z "$tmp" ]; then
finishInput="1"
fi
done
echo -n "Maintainer:"
read maintainer

空行が渡されるまでdesc varを読み取ります。その後、私は他のものを読みたいです。

現在のスクリプトを実行すると、次のようになります。

Description:
Line 1
Line 2

Maintainer:

最後の空の行を「Maintainer:」で上書きします。

私は解決策を探しましたが、次のような提案のみを見つけました

echo -n "Old line"
echo -e "\r new line"

行に残り、上書きします。私の場合、これは不可能です。

49
Zulakis

"\e[1A"を使用してください。

例では、同じ行のテキストを削除します。

$ echo -n "Old line"; echo -e "\e[0K\r new line"
 new line

前の行に戻りたい場合は、\ e [1Aを使用します。

$ echo "Old line"; echo -en "\e[1A"; echo -e "\e[0K\r new line"
 new line

N行上に移動する場合は、\e[<N>Aを使用します。

72
Igor Chubin

素晴らしい エスケープシーケンスに関するガイド を見つけ、ここでの議論のいくつかを拡張したかった.

ターミナルに書き出すときは、テキストエディタで書くときと同じように、非表示カーソルを移動します。 echoを使用すると、カーソルを次の行に移動する改行文字で出力が自動的に終了します。

$ echo "Hello" && echo " World"
Hello
 World

-nを使用して新しい行を防ぐことができます。この後に再度エコーすると、その行の末尾に追加されます

$ echo -n "Hello" && echo " World"
Hello World

カーソルは元のままなので、それ自体では、-nを使用して前の行を上書きすることはできません。カーソルを左に移動する必要があります。それを行うには、エスケープシーケンスを与える必要があります。エスケープシーケンスは、-eで使用することをechoに知らせ、カーソルを移動するリターンキャリッジ\rを提供してカーソルを移動します。行の始まり。

$ echo -n "Hello" && echo -e "\rWorld"
World

それはうまくいったように見えるかもしれませんが、何が起こるかを見てください

$ echo -n "A longer sentance" && echo -e "\rShort sentance"
Short sentancence

余分な文字が表示されますか?単に行に書き込むと、それらを書いた文字が変わるだけです。

これを修正するため、上記の受け入れられた回答では、エスケープ文字\e[0Kを使用して、カーソルの後、カーソルが左に移動した後にすべてを消去します。つまり、\rを先頭に移動\e[0Kを消去して終了します。

$ echo -n "A longer sentance" && echo -e "\r\e[0KShort sentance"
Short sentance

Important\eはエスケープシーケンスを開始しますが、zshでは機能しますが、shでは機能せず、必ずしもbashではありませんが、\033はすべてで機能しますそのうちの。スクリプトをどこでも動作させたい場合は、\033を設定する必要があります

$ echo -n "A longer sentance" && echo -e "\r\033[0KShort sentance"
Short sentance

ただし、エスケープ文字を使用するとさらに便利になります。たとえば、\033[1Aはカーソルを前の行に移動するため、前のエコーで-nは不要です。

$ echo "A longer sentance" && echo -e "\r\033[1A\033[0KShort sentance"
Short sentance

\r先頭に移動\033[1A上に移動\033[0K最後に消去

最後に、これは私の本では少し面倒なので、これを関数に変えることができます:

overwrite() { echo -e "\r\033[1A\033[0K$@"; }

$@を使用すると、関数のすべてのパラメーターが文字列に入れられます

$ echo Longer sentance && overwrite Short sentence
Short sentence

もっと知りたい人に役立つことを願っています。

15
DanielM

Dennis Williamsons Comment から関数を作成しました:

function clearLastLine() {
        tput cuu 1 && tput el
}

デニス・ウィリアムソンに感謝

13
Murmel

改行文字echo -n "Something"なしでエコーする場合、次のエコーで\rを使用して、 'cursor'を行の先頭echo -e "\\rOverwrite something"

bash overwrite terminal line

#!/bin/bash

CHECK_MARK="\033[0;32m\xE2\x9C\x94\033[0m"

echo -e "\n\e[4mDoing Things\e[0m"
echo -n "doing thing 1..."
sleep 1
echo -e "\\r${CHECK_MARK} thing 1 done"

新しい文字列が古い文字列よりも短い場合でも、古い文字列の末尾が表示されることに注意してください。上記のgifのdone..に注意してください。

6
Derek Soike
#!/bin/bash

echo "Description:"
while test -z $finishInput; do
 read -s tmp
 desc="$desc"$'\n'"$tmp"
 if [ -z "$tmp" ]; then
 finishInput=1
 else
    echo $tmp
 fi
 #echo "fi="$finishInput;
done
echo -n "Maintainer:"
read maintainer

このソリューションは空の行を回避しますが、行が完了するまで入力はエコーされません。

ヒント:bashの私のバージョンは「[$ finishInput -eq 0]」を受け入れませんでした。

1
Michael Besteck

スクリプトをループで実行し、スクロールバックを爆破したくない場合は、次のパターンを使用できます。

while sleep 10s; do 
  echo -n $(script)
  echo -n -e "\e[0K\r"
done

scriptコマンドを独自のものに置き換えるだけです。

0
maxywb