stat("/opt/wine-staging/bin/ls", 0x7ffc6bf028c0) = -1 ENOENT (No such file or directory)
stat("/home/oli/bin/ls", 0x7ffc6bf028c0) = -1 ENOENT (No such file or directory)
stat("/usr/local/sbin/ls", 0x7ffc6bf028c0) = -1 ENOENT (No such file or directory)
stat("/usr/local/bin/ls", 0x7ffc6bf028c0) = -1 ENOENT (No such file or directory)
stat("/usr/sbin/ls", 0x7ffc6bf028c0) = -1 ENOENT (No such file or directory)
stat("/usr/bin/ls", 0x7ffc6bf028c0) = -1 ENOENT (No such file or directory)
stat("/sbin/ls", 0x7ffc6bf028c0) = -1 ENOENT (No such file or directory)
stat("/bin/ls", {st_mode=S_IFREG|0755, st_size=110080, ...}) = 0
在评估命令时,
>
首先解决重定向:所以到ls
运行时,输出文件已经创建。这也是为什么
>
在同一命令中使用重定向读取和写入同一文件会截断文件的原因;当命令运行时,文件已经被截断:避免这种情况的技巧:
<<<"$(ls)" > ls.out
(适用于需要在重定向解决之前运行的任何命令)命令替换在评估外部命令之前
ls
运行,因此在创建之前运行ls.out
:ls | sponge ls.out
(适用于需要在重定向解决之前运行的任何命令)sponge
仅当管道的其余部分已完成执行时才写入文件,因此在创建ls
之前运行(随包提供):ls.out
sponge
moreutils
ls * > ls.out
(适用于ls > ls.out
的具体情况)文件名扩展在重定向解决之前执行,因此
ls
将在其参数上运行,其中不包含ls.out
:关于为什么在程序/脚本/任何运行之前解决重定向,我没有看到强制这样做的具体原因,但我看到了两个更好的原因:
不事先重定向 STDIN 会使程序/脚本/任何东西在 STDIN 被重定向之前保持不变;
不预先重定向 STDOUT 必须使 shell 缓冲程序的/脚本的/任何输出,直到 STDOUT 被重定向;
所以在第一种情况下浪费时间,在第二种情况下浪费时间和内存。
这就是我的想法,我并不是说这些是实际原因;但我想总而言之,如果有人可以选择,出于上述原因,他们无论如何都会选择重定向。
来自
man bash
:第一句话,建议
stdin
在执行命令之前将输出发送到除重定向之外的其他位置。因此,为了重定向到文件,文件必须首先由外壳本身创建。为避免有文件,我建议您先将输出重定向到命名管道,然后再重定向到文件。注意使用 将
&
终端控制权返回给用户但为什么?
想想这个——输出会在哪里?一个程序有像
printf
,sprintf
,之类的函数puts
,默认情况下都去stdout
,但是如果文件首先不存在,它们的输出可以去文件吗?就像水一样。不先把玻璃放在水龙头下面,你能得到一杯水吗?我不同意目前的答案。必须在命令运行之前打开输出文件,否则命令将无处可写其输出。
这是因为在我们的世界中“一切都是文件” 。到屏幕的输出是 SDOUT(又名文件描述符 1)。对于要写入终端的应用程序,它会打开fd1 并像文件一样写入它。
当您在 shell 中重定向应用程序的输出时,您正在更改 fd1,使其实际上指向文件。当您使用管道时,您将一个应用程序的 STDOUT 更改为另一个应用程序的 STDIN (fd0)。
但这一切都很好,但是您可以很容易地了解它是如何与
strace
. 这是很重的东西,但这个例子很短。在其中
strace.out
,我们可以看到以下亮点:这打开
ls.out
为fd3
. 只写。如果存在则截断(覆盖),否则创建。这有点杂耍。我们将 STDOUT (fd1) 分流到 fd10 并将其关闭。这是因为我们没有用这个命令向真正的 STDOUT 输出任何东西。它通过复制写句柄
ls.out
并关闭原始句柄来完成。这是它搜索可执行文件。一个教训也许没有很长的路;)
然后命令运行并且父级等待。在此操作期间,任何 STDOUT 都将实际映射到打开的文件句柄
ls.out
。当子进程发出SIGCHLD
时,这告诉父进程它已经完成并且它可以恢复。它以更多的杂耍和关闭结束ls.out
。为什么有这么多杂耍?不,我也不完全确定。
当然你可以改变这种行为。您可以使用类似的东西缓冲到内存
sponge
中,并且从执行的命令中将不可见。我们仍在影响文件描述符,但不是以文件系统可见的方式。还有一篇关于在 shell 中实现重定向和管道运算符的好文章。这显示了如何实现重定向,因此
$ ls > ls.out
可能如下所示: