Простая индикация выполнения в консоли

Каков самый простой способ указать прогресс работы в консоли? Вывод процента будет достаточным, индикатор выполнения не нужен.

Используя только print создаст много строк, я хочу только одну изменяющуюся строку в терминале.

Ответ 1

Самый простой способ - сделать то, что делают wget и другие программы: распечатать возврат каретки и код стирания ANSI перед информацией о ходе работы, возвращая курсор к началу строки и заменяя существующий текст. Например:

import Control.Monad
import Control.Concurrent
import System.IO
import Text.Printf

putProgress :: String -> IO ()
putProgress s = hPutStr stderr $ "\r\ESC[K" ++ s

drawProgressBar :: Int -> Rational -> String
drawProgressBar width progress =
  "[" ++ replicate bars '=' ++ replicate spaces ' ' ++ "]"
  where bars = round (progress * fromIntegral width)
        spaces = width - bars

drawPercentage :: Rational -> String
drawPercentage progress = printf "%3d%%" (truncate (progress * 100) :: Int)

main :: IO ()
main = do
  forM_ [0..10] $ \i -> do
    let progress = fromIntegral i / 10
    putProgress $ drawProgressBar 40 progress ++ " " ++ drawPercentage progress
    threadDelay 250000
  putProgress "All done."
  hPutChar stderr '\n'

Ключевая вещь здесь заключается в том, чтобы не печатать новую строку, чтобы вы могли вернуться к началу строки в следующем обновлении прогресса.

Конечно, вы можете просто распечатать процент здесь и отбросить панель, но панель более крутая:)

Ответ 2

Если я хочу что-то действительно быстрое и грязное, то, что я обычно делаю, это просто напечатать последовательность точек. Каждый раз, когда был прогресс "немного больше", я просто пишу еще одну точку (без новой строки). Я настраиваю меру "немного прогресса", так что точки появляются вокруг временного масштаба точки в секунду. Не очень сложный, но он показывает, что программа что-то делает.

Если у вас действительно есть какая-то мера того, сколько будет общего "прогресса" (я часто этого не делаю, но это предлагается вашим упоминанием о процентах), тогда вы можете просто объявить всю программу X точек и печатать каждый раз, когда вы делаете ход 1/X.