同じ行でエコーを表示および更新する方法


112

私はBashに以下を持っています(Linuxの場合)

for dir in Movies/*
do
  (cd "$dir" && pwd|cut -d \/ -f5|tr -s '\n' ', ' >> ../../movielist &&
  exiftool * -t -s3 -ImageSize -FileType|tr -s '\t' ',' >> ../../movielist )
echo "Movie $movies - $dir ADDED!"
let movies=movies+1
done

しかし、「エコー」が次の行に次のエコーを表示するようにしたいので(最後のエコー出力と連結せずに置き換えます)、更新しているように見せます。パーセントのプログレスバーが同じ行に表示される方法と同様です。

回答:


196

さてman echo、このページを正しく読みませんでした。

echoには、3番目のエスケープ文字を追加した場合にこれを実行できる2つのオプションがありました。

2つのオプションは-nおよび-eです。

-n末尾の改行は出力されません。これにより、エコーするたびに新しい行に移動する必要がなくなります。

-e バックスラッシュエスケープシンボルを解釈できます。

これに使用したいエスケープシンボルを推測します\r。はい、キャリッジリターンで最初に戻るので、視覚的には同じ行で更新しているように見えます。

したがって、エコーラインは次のようになります。

echo -ne "Movie $movies - $dir ADDED!"\\r

バッシュがそれを殺さないように、私はエスケープシンボルをエスケープしなければなりませんでした。そのため\、そこに2つのシンボルが表示されます。

ウィリアムが述べたprintfように、このような同様の(そしてさらに広範囲な)タスクも実行できます。


12
将来へのメモです。printfはまったく同じことを行いますが、オプションはありません。利点は、printfが一般にすべての環境とOSで同様に動作するのに対し、echoは非常に異なる動作をする場合があることです。クロスプラットフォームスクリプトの場合(または、それを気にする可能性がある場合)、printfを使用するのがベストプラクティスです。
William T Froggard 16

8
printf a; printf b出力ab--- printf a\\r; printf b出力b--- printf a\\r; sleep 1; printf b出力a、次にb
XavierStuvw 2017

64

私がよく理解していれば、エコーを次の行で置き換えることができます。

echo -ne "Movie $movies - $dir ADDED! \033[0K\r"

以下は、その動作を理解するために実行できる小さな例です。

#!/bin/bash
for pc in $(seq 1 100); do
    echo -ne "$pc%\033[0K\r"
    sleep 1
done
echo

zshの上と思われるK必要はなく、実際に手紙K.として出します
mknaf

1
素晴らしい例-私にとって、最初のハッシュバンは重要でした
Felix Eve

22

残りの回答はかなり良いですが、誰かが複数行エコーを置換/更新するための解決策を探してここに来た場合に備えて、いくつかの追加情報を追加したいと考えました。

それでは、皆さんと例を共有したいと思います。次のスクリプトはCentOSシステムで試行され、基本的にシステムの詳細な時間情報を出力する「timedatectl」コマンドを使用しています。

出力に複数の行が含まれ、以下の例で完全に機能するため、そのコマンドを使用することにしました。

#!/bin/bash
while true; do
  COMMAND=$(timedatectl) #Save command result in a var.
  echo "$COMMAND" #Print command result, including new lines.

  sleep 3 #Keep above's output on screen during 3 seconds before clearing it

  #Following code clears previously printed lines
  LINES=$(echo "$COMMAND" | wc -l) #Calculate number of lines for the output previously printed
  for (( i=1; i <= $(($LINES)); i++ ));do #For each line printed as a result of "timedatectl"
    tput cuu1 #Move cursor up by one line
    tput el #Clear the line
  done

done

上記は、 "timedatectl "永久に出力し、以前のエコーを更新された結果で置き換えます。

このコードは例にすぎませんが、ニーズによっては最適なソリューションではない可能性があります。(少なくとも視覚的には)ほとんど同じことを行う同様のコマンドは、 "watch -n 3 timedatectl "です。

しかし、それは別の話です。:)

お役に立てば幸いです。


3

これは便利です。試してみて、必要に応じて変更してください。

#! bin/bash
for load in $(seq 1 100); do
    echo -ne "$load % downloded ...\r"
    sleep 1
done
echo "100"
echo "Loaded ..."

3

あなたはこれを試すことができます..私自身のバージョン..

funcc() {
while true ; do 
for i in \| \/ \- \\ \| \/ \- \\; do 
  echo -n -e "\r$1  $i  "
sleep 0.5
done  
#echo -e "\r                                                                                      "
[ -f /tmp/print-stat ] && break 2
done
}

funcc "Checking Kubectl" & &>/dev/null
sleep 5
touch /tmp/print-stat
echo -e "\rPrint Success                  "

1

私のお気に入りの方法は、50にスリープを行うと呼ばれます。ここで、i変数はエコーステートメント内で使用する必要があります。

for i in $(seq 1 50); do
  echo -ne "$i%\033[0K\r"
  sleep 50
done
echo "ended"

これはいいですが、カーソルが最初の文字を覆い隠しています。エコー内のいくつかのスペースがそれを回避できると思います。
マラソン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.