Print something in console in the same place of the previous echo, with a sort of negative echo

12,731

The typical way of doing this is not to erase a single character, but to go back to the start of the line using a carriage return (\r):

printf "89%%"; sleep 1; printf "\r90%%\n"

Note that this doesn’t clear the line, so you need to take care of that if necessary. Simple options are adding spaces to the end, or making the output fixed-width (e.g. printf "%2d%%\n" 1 gives a leading space).

There are terminal escapes which will allow you to move around and clear parts of the screen, the CSI sequences, but they are terminal-dependent (although in practice VT100 escapes are supported everywhere now). For example

printf "89%%"; sleep 1; printf "\e[3D90%%\n"

uses ␛[3D to move three characters to the left, and writes over them (assuming your printf supports \e);

printf "89%% hello"; sleep 1; printf "\e[0E\e[K90%%\n"

uses ␛[0E to move to the beginning of the current line, and ␛[K to clear to the end of the line (assuming your terminal supports those sequences).

tput provides a terminal- and printf-agnostic way of accessing these sequences:

printf "89%%"; sleep 1; tput cub 3; tput el; printf "90%%\n"

will move the cursor to the left three times (cub 3) and clear to the end of the line (el), using whatever character sequence is appropriate for the current terminal;

printf "89%% hello"; sleep 1; tput hpa 0; tput el; printf "90%%\n"

will move the cursor to the left-most column (hpa 0) and clear to the end of the line.

man terminfo will tell you what “capability name” to use with tput.

(Note that a lot of the specifics of the examples above assume that all your output is on the same line. They’re not supposed to be fool-proof, only to illustrate various approaches.)

For similar screen control in PHP scripts, you could look at the PECL ncurses extension.

Share:
12,731

Related videos on Youtube

user3450548
Author by

user3450548

Updated on September 18, 2022

Comments

  • user3450548
    user3450548 almost 2 years

    In bash you can cast a command named clear to clear all the screen commands.

    And with echo you can print whatever you want onscreen..

    In my simple scripts I often have the need of print a percentage of what's being done with my commands..

    So I could do something like..

    echo "89%"
    echo "90%"
    echo "91%"
    

    and so on..

    what I hate is getting the screen full of percent updates...

    89%
    90%
    91%
    ...
    

    what I would like is to learn if there's a special character combination (eg. "\033[01;31m") that could be echoed with bash or php echo and tells the console "remove the last previous printed character.."

    doing so by using something like: (php example)

    echo str_repeat($neg_character, strlen($last_percentage_update_string));
    echo $new_percentage_update_string;
    

    I would get the new string printed at the exact position of the previous one without have the screen full of lines

    Otherwise I look for an approach to do the same in other ways always using bash and php scripts (please include actual working examples at least with a debian9 console and php7)

  • Stéphane Chazelas
    Stéphane Chazelas almost 6 years
    One can usually use tput cub 3 to move the cursor back by 3 columns without having to hardcode the sequence (and tput el to erase the line).
  • user1730706
    user1730706 almost 6 years
    1. \e isnt portable 2. neither is \e[0E
  • Stephen Kitt
    Stephen Kitt almost 6 years
    Thanks @Steven, I’d mentioned that the sequences were terminal-dependent but I’ve added some more qualifiers.
  • JdeBP
    JdeBP almost 6 years
    One could use ech for erasure. And moving backwards by 3 positions has a gotcha, and two possible optimizations that full-screen programs tend to use. But both optimizations and erasure are overkill for simple current-line-only terminal stuff, when one follows that advice to use a fixed-width format specifier. Don't forget that 100 is 3 digits long, by the way. (-:
  • Stephen Kitt
    Stephen Kitt almost 6 years
    Good points @JdeBP, thanks. Once you hit 100%, I sure hope you no longer need progress updates ;-).
  • user3450548
    user3450548 almost 6 years
    In bash you could use tput but I often run scripts in php as in the question said, I think that system("tput...") will not work in php.. i should try a php -f script.php in terminal and see if it's possible to erase characters..
  • Stephen Kitt
    Stephen Kitt almost 6 years
    @user3450548 the ncurses PECL extension might do the trick for PHP scripts.
  • user3450548
    user3450548 almost 6 years
    @StephenKitt can you provide an example ? I'm not sure i can use the ncurses PECL however..
  • Marius
    Marius almost 6 years
    Some of the answer's incorrect (as well as a few errors in the comments). Some reading (and testing) would be helpful.
  • Stephen Kitt
    Stephen Kitt almost 6 years
    Thanks for the feedback, @Thomas. I tested everything on a couple of the systems I have available, but I dare say they don’t work everywhere; as mentioned, the examples are just that, examples, whose results depend on the terminal and printf implementation used. I imagine you have pointers to documentation I should read — would you care to share some?
  • user3450548
    user3450548 almost 6 years
    I would feel ok if a solution could work for php and debian9
  • Marius
    Marius almost 6 years
    ECMA-48 is a good place to start, for your answer.
  • Marius
    Marius almost 6 years
    Besides the documentation, I noticed that the corresponding test in vttest wasn't clear enough, and improved it to make the problem obvious, and then checked the usual selection of terminal emulators, found none which uses the incorrect behavior.