3

We know to overwrite bar.txt, we can use this:

echo "foo" > bar.txt

but how can we overwrite to the standard output? I tried this command:

echo "foo" >

but it failed. I want this because I want to print something like this:

Hello  

world

I'm 

HERE 

one word at a time and I want to delete the previous word (one word at a time on standard output).

slm
  • 369,824
user78050
  • 1,065
  • 1
    Your question is not clear. > operator won't append to the file actually it overwrites the file.And if you just say echo "foo" or echo "foo" >&1 it prints on stdout. – Thushi Aug 21 '14 at 12:06
  • I want to delete the word which printed on stdout then add another word – user78050 Aug 21 '14 at 12:11
  • Can you add the source of the output, how do you plan to get the sources? – Braiam Aug 21 '14 at 12:20
  • 2
    I'm under the impression you're confusing stdout (the default destination programs write their output to), with terminal. – Stéphane Chazelas Aug 21 '14 at 12:35

5 Answers5

6

echo always outputs to its stdout1. echo foo always does a write(1, "foo\n").

When you do echo foo > file, the shell changes the stdout for the echo command to a new file file. echo foo then still does a write(1, "foo\n") but this time its stdout (its file descriptor 1) points to file, not to the stdout it inherits from the shell.

If you want to write to stdout without that stdout being redirected, just write:

echo foo

If you want the resource pointed to by stdout to be reopen (and truncated) before each echo, then that's trickier.

On Linux (and Linux only), you can do:

echo foo > /dev/fd/1
echo bar > /dev/fd/1
# now the file stdout points to (if it's a regular file) contains "bar"

On Linux, /dev/fd/1 is a symlink to the file that is open on stdout. So opening it again with > will truncate it (on other Unices, > /dev/fd/n is like dup2(n,1) so it won't truncate the file). That won't work if stdout goes to a socket though.

Otherwise, you can call ftruncate() on stdout (fd 1) to truncate it:

perl -e 'truncate STDOUT,0'
echo foo
perl -e 'truncate STDOUT,0'
echo bar

If instead, you want those words, when stdout is a terminal to overwrite each other on the screen, you can use terminal control characters to affect the cursor positioning.

 printf %s FOO
 printf '\r%s' BAR

will have BAR overwrite FOO because \r is the control characters that instructs the terminal to move the cursor to the beginning of the line.

If you do:

printf %s FOOBAR
printf '\r%s' BAZ

however, you'll see BAZBAR on the screen. You may want to use another control sequence to clear the line. While \r as meaning carriage return is universal, the control sequence to clear the screen varies from one terminal to the next. Best is to query the terminfo database with tput to find it out:

clr_eol=$(tput el)
printf %s FOOBAR
printf '\r%s%s' "$clr_eol" BAZ

1 if using the Korn or Z shell, another outputting command that supports writing to other file descriptors is print: print -u2 FOO for instance writes FOO to print's stderr. With echo and in Bourne-like shells, you can do echo >&2 FOO to achieve the same result. echo is still writing to its stdout, but its stdout has been made a duplicate of the shell's stderr using the >&2 shell redirection operator

2

You can say,

$ clear && printf "before" && sleep 1 && clear && printf "after\n"

For your Hello world,

$ clear && printf "Hello" && sleep 1 && clear && printf "World" && sleep 1 && clear && printf "I'm" && sleep 1 && clear && printf "Here\n"

Thushi
  • 9,498
1

If you're printing to a terminal anyway, you maybe just want to omit the newline (-n) and have an explicit carriage return instead:

echo -en 'hello, dear\r'; sleep 5; echo -en 'world\r'; echo

(Note that you'll want to space-pad your strings to overwrite them completely.)

0

> actually redirects stdout to a file. What you try to do, is in other words to redirect stdout to stdout itself - which doesn't make much sence. You got stdout already - > just tells the shell to put the output into a file instead of to the screen.

What you can do, is to redirect the output to virtual-terminal or pseudo-terminal you have access to (eg. command > /dev/pts/2 ), that way you can send the output from a command to another terminal then the one it's running in.

You can also create a named-pipe (fifo), whcih appears as a file. One command can write (its stdout) to this file, while another command can read (to its stdin) from it.

0

If you want to use echo instead of Thushi's solution with printf, have a look at the -e option of the echo command. This allows you to use certain escape sequences, including \b for backspace. Together with the -n option which supresses newlines you can do this:

 echo -n "Hello" && sleep 10 && echo -n -e "\b\b\b\b\bworld"
ph0t0nix
  • 1,147