我们知道要覆盖bar.txt
,我们可以使用这个:
echo "foo" > bar.txt
但我们如何覆盖标准输出呢?我尝试了这个命令:
echo "foo" >
但它失败了。我想要这个是因为我想打印这样的东西:
Hello
world
I'm
HERE
一次一个单词,我想删除前一个单词(标准输出上一次一个单词)。
答案1
echo
始终输出到其标准输出1。echo foo
总是做一个write(1, "foo\n")
.
当您执行此操作时echo foo > file
,shell 会将echo
命令的标准输出更改为新file
文件。echo foo
then 仍然执行 awrite(1, "foo\n")
但这次它的 stdout (其文件描述符 1)指向file
,而不是它从 shell 继承的 stdout。
如果您想写入标准输出而不需要该标准输出重定向, 写吧:
echo foo
如果您希望 stdout 指向的资源在每个之前重新打开(并截断)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"
在 Linux 上,/dev/fd/1
是指向在 stdout 上打开的文件的符号链接。因此再次打开它>
会截断它(在其他 Unices 上,> /dev/fd/n
就像dup2(n,1)
这样它不会截断文件)。如果标准输出连接到套接字,那将不起作用。
否则,您可以调用ftruncate()
stdout (fd 1) 来截断它:
perl -e 'truncate STDOUT,0'
echo foo
perl -e 'truncate STDOUT,0'
echo bar
相反,如果你想要这些词,当 stdout 是终端时要在屏幕上相互覆盖,可以使用终端控制字符来影响光标定位。
printf %s FOO
printf '\r%s' BAR
BAR 将会覆盖 FOO,因为 FOO\r
是指示终端将光标移动到行首的控制字符。
如果你这样做:
printf %s FOOBAR
printf '\r%s' BAZ
但是,您会BAZBAR
在屏幕上看到。您可能需要使用另一个控制序列来清除线路。虽然\r
回车是通用的,但清除屏幕的控制序列因终端而异。最好的方法是查询 terminfo 数据库来tput
找到它:
clr_eol=$(tput el)
printf %s FOOBAR
printf '\r%s%s' "$clr_eol" BAZ
1如果使用 Korn 或 Z shell,另一个支持写入其他文件描述符的输出命令是print
:print -u2 FOO
例如写入FOO
' print
s stderr。使用echo
类似 Bourne 的 shell,您可以echo >&2 FOO
达到相同的结果。echo
仍在写入其标准输出,但已使用 shell>&2
重定向运算符将其标准输出复制为 shell 的 stderr
答案2
你可以说,
$clear && printf "before" && sleep 1 && clear && printf "after\n"
为了你的世界,
$clear && printf "Hello" && sleep 1 && clear && printf "World" && sleep 1 && clear && printf "I'm" && sleep 1 && clear && printf "Here\n"
答案3
如果您无论如何都要打印到终端,您可能只想省略换行符 ( -n
) 并使用显式回车符:
echo -en 'hello, dear\r'; sleep 5; echo -en 'world\r'; echo
(请注意,您需要用空格填充字符串以完全覆盖它们。)
答案4
如果您想使用echo
代替 Suchhi 的解决方案printf
,请查看-e
该echo
命令的选项。这允许您使用某些转义序列,包括\b
退格键。与-n
抑制换行符的选项一起,您可以执行以下操作:
echo -n "Hello" && sleep 10 && echo -n -e "\b\b\b\b\bworld"