Is it possible to get the output of a command - for example tar
- to write each line of output to one line only?
Example usage:
tar -options -f dest source | [insert trickery here]
and the output would show every file being processed without making the screen move: each output overwrites the last one. Can it be done?
Edit: we seem to have a working answer, but lets take it further: How about doing the same, but over 5 lines? You see a scrolling output that doesn't affect the rest of the terminal. I think I've got an answer, but I'd like to see what you guys think.
Silencing Output To silence the output of a command, we redirect either stdout or stderr — or both — to /dev/null. To select which stream to redirect, we need to provide the FD number to the redirection operator.
In the command, change "YOUR-COMMAND" with your command and "c:\PATH\TO\FOLDER\OUTPUT. txt" with the path and file name to store the output. In the command, change "YOUR-COMMAND" with your command and "c:\PATH\TO\FOLDER\OUTPUT. txt" with the path and filename to store and view the output.
Redirect Output to a File Only To redirect the output of a command to a file, type the command, specify the > or the >> operator, and then provide the path to a file you want to the output redirected to. For example, the ls command lists the files and folders in the current directory.
Replace the newlines with carriage returns.
tar -options -f dest source | cut -b1-$(tput cols) | sed -u 'i\\o033[2K' | stdbuf -o0 tr '\n' '\r'; echo
Explanation:
cut -b1-$(tput cols)
: Truncates the output of tar if it is longer than the terminal is wide. Depending on how little you want your terminal to move, it isn't strictly necessary.
sed -u 'i\\o033[2K'
: Inserts a line blank at the beginning of each line. The -u
option to sed puts it in unbuffered mode. stdbuf -oL sed 'i\\033[2K'
would work equally as well.
stdbuf -o0 tr '\n' '\r'
: Uses tr
to exchange newlines with carriage returns. Stdbuf makes sure that the output is unbuffered; without the \n
's, on a line buffered terminal, we'd see no output.
echo
: Outputs a final newline, so that the terminal prompt doesn't eat up the final line.
For the problem your edit proposes:
x=0;
echo -e '\e[s';
tar -options -f dest source | while read line; do
echo -en "\e[u"
if [ $x gt 0 ]; then echo -en "\e["$x"B"; fi;
echo -en "\e[2K"
echo -n $line | cut -b1-$(tput cols);
let "x = ($x+1)%5";
done; echo;
Feel free to smush all that onto one line. This actually yields an alternative solution for the original problem:
echo -e '\e[s'; tar -options -f dest source | while read line; do echo -en "\e[u\e2K"; echo -n $line | cut -b1-$(tput cols); done; echo
which neatly relies on nothing except VT100 codes.
Thanks to Dave/tripleee for the core mechanic (replacing newlines with carriage returns), here's a version that actually works:
tar [opts] [args] | perl -e '$| = 1; while (<>) { s/\n/\r/; print; } print "\n"'
Setting $|
causes perl to automatically flush after every print
, instead of waiting for newlines, and the trailing newline keeps your last line of output from being (partially) overwritten when the command finishes and bash prints a prompt. (That's really ugly if it's partial, with the prompt and cursor followed by the rest of the line of output.)
It'd be nice to accomplish this with tr
, but I'm not aware of how to force tr
(or anything similarly standard) to flush stdout.
Edit: The previous version is actually ugly, since it doesn't clear the rest of the line after what's been output. That means that shorter lines following longer lines have leftover trailing text. This (admittedly ugly) fixes that:
tar [opts] [args] | perl -e '$| = 1; $f = "%-" . `tput cols` . "s\r"; $f =~ s/\n//; while (<>) {s/\n//; printf $f, $_;} print "\n"'
(You can also get the terminal width in more perl-y ways, as described here; I didn't want to depend on CPAN modules though.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With