Overwriting Command Line Output With PHP

The other day I was trying to print some output to the command line and then overwrite the output afterwards. It turns out that there are a couple of ways to do this so I thought I would detail a few of them here.

By far the simplest way of doing this is to run the "clear" command, which we can run via the system() function in PHP. This will clear the output of the command line ready for you to print out whatever you need. The downside to this is that the entire terminal window is cleared. Another downside is that once the output is complete scrolling up will reveal the output that was cleared out.

The following will clear the console, print out "Please wait", wait 5 seconds and then replace that with "Done".

system('clear');
echo 'Please wait';
sleep(5);
system('clear');
echo 'Done';

Replacing the line without moving the entire screen around is a much better technique. This can be done using the "\r" character. All you need to do is print out that character and whatever you print out next will replace the current line. The following will to the same as the previous example, but in this case only the last printed line will be replaced.

echo "Please wait";
sleep(5);
echo "\rDone";

An alternative to this is to use ANSI control sequences to control where the cursor is within the command terminal. In order to do this we need to print out an "Esc" character (the ANSI character 27), followed by the ANSI instruction "[0G" to move the cursor to the first column. When we print out the next string, which overwrites the previously written string.

echo "Please wait";
sleep(5);
echo chr(27) . "[0G";
echo "Done";

We can use this technique to overwrite characters across multiple lines on the command line. To do with we need to count how many lines of content we have printed out and use the ANSI control sequence to move to the start of the line and move to the first line in the output.

In the following example we are printing out two lines of output and then sleeping for 5 seconds. After that has finished we are using the "[0G" ANSI control sequence to move the cursor to the start of the line and then the "[2A" to move two lines up. Now, when we print "Done" the output replaces the previous output.

echo "Please wait" . PHP_EOL;
echo "Working..." . PHP_EOL;
sleep(5);
echo chr(27) . "[0G";
echo chr(27) . "[2A";
echo "Done";

We can collect all of this together into a function that will replace all output that has previously been printed.

function replaceCommandOutput(array $output) {
  static $oldLines = 0;
  $numNewLines = count($output) - 1;

  if ($oldLines == 0) {
    $oldLines = $numNewLines;
  }

  echo implode(PHP_EOL, $output);
  echo chr(27) . "[0G";
  echo chr(27) . "[" . $oldLines . "A";

  $numNewLines = $oldLines;
}

To use this function we need to pass an array of the bits of output we want to print. Here is an example of doing this in a loop to replace the output continuously.

while (true) {
  $output = [];
  $output[] = 'First Line';
  $output[] = 'Time: ' . date('r');
  $output[] = 'Random number: ' . rand(100, 999);
  $output[] = 'Random letter: ' . chr(rand(65, 89));
  $output[] = 'Last Line';
  replaceCommandOutput($output);
  usleep(100000);
}

This will print out the following, which will entirely update every 0.1 of a second.

First Line
Time: Sun, 12 Apr 2020 20:20:52 +0000
Random number: 551
Random letter: T
Last Line

Note that I have not tested any of these methods on Windows terminal, so you might not be able to get the same effect working.

Do you know of any techniques that can be used to do this? Post them in the comments below.

Add new comment

The content of this field is kept private and will not be shown publicly.
CAPTCHA
1 + 1 =
Solve this simple math problem and enter the result. E.g. for 1+3, enter 4.
This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.