如何使用回声覆盖标准输出?

use*_*050 3 echo text-processing stdout

我们知道覆盖bar.txt,我们可以使用这个:

echo "foo" > bar.txt
Run Code Online (Sandbox Code Playgroud)

但是我们如何覆盖标准输出呢?我试过这个命令:

echo "foo" >
Run Code Online (Sandbox Code Playgroud)

但它失败了。我想要这个,因为我想打印这样的东西:

Hello  

world

I'm 

HERE 
Run Code Online (Sandbox Code Playgroud)

一次一个词,我想删除前一个词(在标准输出中一次一个词)。

Sté*_*las 5

echo总是输出到它的 stdout 1。echo foo总是做一个write(1, "foo\n").

当您这样做时echo foo > file,shell 会将echo命令的标准输出更改为一个新file文件。echo foothen 仍然执行 awrite(1, "foo\n")但这次它的标准输出(它的文件描述符 1)指向file,而不是它从外壳继承的标准输出。

如果您想在不重定向标准输出的情况下写入标准输出,只需编写:

echo foo
Run Code Online (Sandbox Code Playgroud)

如果您希望 stdout 指向的资源在 each 之前重新打开(并截断)echo,那么这就比较棘手了。

在 Linux(仅限 Linux)上,您可以执行以下操作:

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

在 Linux 上,/dev/fd/1是指向在 stdout 上打开的文件的符号链接。所以再次打开它>会截断它(在其他 Unices 上,> /dev/fd/n就像dup2(n,1)这样它不会截断文件)。如果 stdout 转到套接字,那将不起作用。

否则,您可以调用ftruncate()stdout (fd 1) 来截断它:

perl -e 'truncate STDOUT,0'
echo foo
perl -e 'truncate STDOUT,0'
echo bar
Run Code Online (Sandbox Code Playgroud)

如果相反,您想要这些话,当 stdout 是终端在屏幕上相互覆盖时,您可以使用终端控制字符来影响光标定位。

 printf %s FOO
 printf '\r%s' BAR
Run Code Online (Sandbox Code Playgroud)

将有 BAR 覆盖 FOO 因为\r是指示终端将光标移动到行首的控制字符。

如果你这样做:

printf %s FOOBAR
printf '\r%s' BAZ
Run Code Online (Sandbox Code Playgroud)

但是,您会BAZBAR在屏幕上看到。您可能希望使用另一个控制序列来清除该行。虽然\r回车的含义是通用的,但清除屏幕的控制顺序因终端而异。最好是查询 terminfo 数据库tput以找出它:

clr_eol=$(tput el)
printf %s FOOBAR
printf '\r%s%s' "$clr_eol" BAZ
Run Code Online (Sandbox Code Playgroud)

1,如果使用了Korn或Z壳,另一个输出命令支持写入其他文件描述符是print:print -u2 FOO例如写入FOO到print的标准错误。使用echo和在 Bourne-like shell 中,您可以echo >&2 FOO实现相同的结果。echo仍在写入其标准输出,但其标准输出已使用>&2shell 重定向运算符复制了 shell 的标准错误