当前位置: 首页 > 科技观察

Bash中的&符号和文件描述符

时间:2023-03-12 03:10:36 科技观察

了解如何使用带尖括号的“&”并从命令行获取更多信息。在我们探索大多数链式Bash命令中出现的所有杂项符号(&、|、;、>、<、{、[、(,)、]、}等)的过程中,我们一直在研究&象征。上次,我们了解了如何使用&将可能长时间运行的进程置于后台。但是,&与尖括号<结合也可以用于管道输出或输出到别处。在前面关于尖括号的教程中,您看到了如何使用>,如下所示:ls>list.txt将ls输出通过管道传输到list.txt文件。我们现在看到的是简写:ls1>list.txt在这种情况下,1是指向标准输出(stdout)的文件描述符。以类似的方式,2指向标准错误输出(stderr):ls2>error.log所有错误消息都通过管道传输到error.log文件。回顾一下:1>是标准输出(stdout),2>是标准错误输出(stderr)。第三个标准文件描述符0<是标准输入(stdin)。您可以看到它是一个输入,因为箭头(<)指向0,而对于1和2,箭头(>)指向外部。标准文件描述符有什么用?如果您阅读过本系列,那么您已经多次使用stdout(1>)的简写形式:>。例如,当(如果)您知道您的命令将抛出错误时,像stderr(2)这样的东西也很方便,但是Bash告诉您一些事情是没有用的,您不需要看到它。如果你想在home/目录下创建一个目录,eg:mkdirnewdir如果newdir/已经存在,mkdir会显示错误。但是你为什么要关心这些呢?(好吧,在某些情况下您可能会关心,但并非总是如此。)在一天结束时,newdir以某种方式让您填写一些东西。您可以通过将错误消息推入空白(即`/dev/null)来抑制错误消息:mkdirnewdir2>/dev/null这不仅仅是“让我们不要看到丑陋和不相关的错误消息,因为它们非常烦人”因为在某些情况下在某些情况下,错误消息可能会在其他地方导致一连串错误。例如,您想在/etc中查找所有.service文件。你可以这样做:find/etc-iname"*.service"但事实证明,在大多数系统上,find显示的错误会有很多行,因为普通用户没有对/etc权限下的某些文件夹的读取权限。这使得读取正确的输出变得很麻烦,并且如果find是更大脚本的一部分,它可能导致行中的下一个命令排队。相反,您可以这样做:find/etc-iname"*.service"2>/dev/null并且您只得到您想要的。文件描述符入门对于单独的文件描述符stdout和stderr有一些注意事项。如果要将输出存储在文件中,请执行以下操作:find/etc-iname"*.service"1>services.txt工作正常,因为1>表示“将stdout及其本身stdout(不是stderr)发送到某处”。但是这里有一个问题:如果你想把命令抛出的错误信息记录到一个文件中,但是结果中没有任何错误信息怎么办?上面的命令没有这样做,因为它只写了find的正确结果,而:find/etc-iname"*.service"2>services.txt只写了命令抛出的错误消息。我们如何获得两者?试试这个命令:find/etc-iname"*.service"&>services.txt...Sayhello&again!我们一直在说stdin(0)、stdout(1)和stderr(2)是“文件描述符”。文件描述符是一种特殊的构造,它是文件的通道,用于读取或写入,或两者兼而有之。这来自将所有内容都视为文件的旧UNIX理念。想写入设备?把它当作一个文件。想要写入套接字并通过线路发送数据?把它当作一个文件。想读写文件?好吧,显然,把它当作一个文件。因此,在管理命令输出和错误位置时,将目标视为文件。因此,当您打开它们进行读写操作时,它们都会获得文件描述符。这是一个有趣的效果。例如,您可以将内容从一个文件描述符传输到另一个文件描述符:find/etc-iname"*.service"1>services.txt2>&1这会将stderr定向到stdout,后者通过管道传输到文件services.txt.它再次出现:&向Bash发出信号,表明1是目标文件描述符。标准文件描述符的另一个问题是,当您从一个文件描述符传输到另一个文件描述符时,执行此操作的顺序有点违反直觉。例如,按照上面的命令。看起来走错了路。你也可以这样读:“直接输出到文件,然后错误输出到标准输出。”看起来错误输出会稍后出现,直到输出到stdout(1)完成后才会发送。但这不是文件描述符的工作方式。文件描述符不是文件的占位符,而是文件的输入和/或输出通道。在这种情况下,当您执行1>services.txt时,您的意思是“打开到services.txt的写入管道并保持打开状态”。1是您要使用的管道的名称,它将保持打开状态直到该行结束。如果您仍然认为这是错误的方法,请尝试以下操作:找到/etc-iname"*.service"2>&11>services.txt并注意它是如何不起作用的;请注意错误是如何定向到终端的,而只有非错误输出(即标准输出)被推送到services.txt。这是因为Bash从左到右处理find的每个结果。这样想:当Bash到达2>&1时,stdout(1)仍然是终端的通道。如果findtoBash的结果包含错误,它将被弹出到2,转移到1,并留在终端中!然后在命令结束时,Bash发现您想要打开stdout(1)作为services.txt文件的通道。如果没有错误发生,结果通过通道1进入文件。相比之下,在:find/etc-iname"*.service"1>services.txt2>&11一开始就指向services.txt,所以凡是弹出2的都会导致1,这已经指向了该位置services.txt结束了,这就是它起作用的原因。无论如何,如上所述,&>是“标准输出和标准错误”的缩写,即2>&1。这可能有点多,但别担心。重定向文件描述符在Bash命令行和脚本中很常见。随着本系列的进展,您将了解有关文件描述符的更多信息。