如果重定向失败,将不执行Bash程序


9

在bash中,我注意到,如果使用重定向的命令失败,则在此之前运行的任何程序都不会运行。

例如,此程序打开文件“ a”,并将50个字节写入文件“ a”。但是,运行此命令并将其重定向到权限不足的文件(〜root / log),文件大小“ a”不变。

$ ./write_file.py >> ~root/log
-bash: /var/root/log: Permission denied
cdal at Mac in ~/experimental/unix_write
$ ls -lt
total 16
-rw-rw-r--  1 cdal  staff  0 Apr 27 08:54 a <-- SHOULD BE 50 BYTES

有人会认为程序会运行,捕获所有输出(但也会写入文件“ a”),然后无法将任何输出写入〜root / log。而是永远不会运行该程序。

为什么会这样,bash在执行程序之前如何选择执行的“检查”的顺序?是否还要执行其他检查?

ps我试图确定在cron下运行的程序在重定向到“权限被拒绝”文件时是否真的运行了。


一切都处于良好的工作状态(即,.py文件的所有权和权限),程序可以正常执行。您的问题来自重定向。您无权在/ root目录中写入文件。而且您已经将您重定向stdout到完全做到这一点。因此,即使您的程序已运行,您也不会看到任何输出。
MelBurslan '16

2
梅尔,事实并非如此,该程序从未真正运行过。请参阅下面的答案。
查理·达萨斯

您:“运行write_file.py程序,并将其输出发送到~root/logbash:“对不起,但是您不能写入该文件!” Shell确实在执行应执行的操作。如果它无法执行您要求的操作,这样做,它会立即通知您为什么会出现问题,让您有机会决定如何处理它。如果足够重要,您指定了保存位置,那么ASS | U | ME可以在不保存stdout的情况下运行是不对的
Monty Harder

Answers:


18

这实际上不是排序检查的问题,仅是外壳程序设置顺序的问题。重定向是在运行命令之前设置的;因此,在您的示例中,shell ~root/log在尝试执行涉及的任何操作之前会尝试打开以进行追加./write_file.py。由于无法打开日志文件,因此重定向失败,shell此时将停止处理命令行。

演示此问题的一种方法是获取一个不可执行的文件并尝试运行它:

$ touch demo
$ ./demo
zsh: permission denied: ./demo
$ ./demo > ~root/log
zsh: permission denied: /root/log

这表明./demo当无法设置重定向时,shell甚至都不会看。


哇,就是这么简单吗?我没有意识到重定向是首先完成的。感谢您提供此答案以及其他出色的答案。
查理·达萨斯

6
如果不先完成,输出将写入哪里?
查尔斯·达菲

如果无法编写输出,我们怎么知道运行命令是安全的?也许该命令输出正在从数据存储中删除的信息,并且绝对有必要捕获输出。好东西bash在您修复这些权限之前不会让它运行,是吗?
Monty Harder

11

bash手册页的“重定向”部分(我强调):

执行命令之前,可以使用由Shell解释的特殊符号来重定向其输入和输出。

...

打开或创建文件失败会导致重定向失败。

因此,shell尝试打开的目标文件stdout,但失败,并且根本不执行命令。


非常感谢。我希望手册页中使用“ ...如果无法重定向输出,将不会执行该程序”进行了澄清。
查理·达萨斯

更新; 它在下面隐藏了一些段落。
Murphy

其实,这很清楚。“无法打开或创建文件会导致重定向失败。” 在那里。再次感谢。
查理·达萨斯

3

值得观察的是,外壳程序必须在启动程序之前建立重定向。

考虑您的示例:

./write_file.py >> ~root/log

外壳中发生的是:

  1. 我们(外壳)fork();子进程从其父进程(shell)继承打开文件描述符。
  2. 在子进程中,我们fopen()(扩展)“〜root / log”,并将dup2()其扩展到fd 1(和close()临时fd)。如果fopen()失败,请致电exit()将错误报告给父母。
  3. 仍然在孩子中,我们是exec()“ ./write_file.py”。现在,此过程不再运行任何代码(除非我们执行失败,在这种情况下,我们exit()将错误报告给父级)。
  4. 父母将wait()让孩子终止并处理其退出代码($?至少将其复制到中)。

所以重定向在与孩子发生fork()exec():它以前没有发生过fork(),因为它不能改变shell的标准输出,并在其后可能不会发生exec(),因为文件名和shell的可执行代码现在已经换成了Python程序。父级无法访问子级的文件描述符(即使这样做,也不能保证exec()在第一次写入stdout 之间进行重定向和重定向)。


0

很抱歉通知您,情况恰恰相反。外壳程序需要先打开它的I / O,然后将控制权传递给程序。

tee 在这种情况下可能会有所帮助: ./write_file.py | tee -a ~root/log > /dev/null


tee失败后,Python脚本会不会刚在SIGPIPE上消失?
凯文

并非根据我所做的测试,但我建议您尝试一下。
Julie Pelletier
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.