如何非侵入性地测试对文件的写访问?

use*_*849 27 scripting permissions shell-script files

在 shell 脚本中,如何在不实际尝试修改文件的情况下轻松且非侵入性地测试对文件的写访问权限?

我可以解析 的输出stat,但这看起来非常复杂,而且可能很脆弱,尽管我不确定不同实现和时间的 stat 输出有多少不同。

我可以附加到文件的末尾,看看是否成功,但这有潜在危险,我能想到的两个原因是:

  1. 我现在必须删除添加项,并且万一其他进程写入文件,这会立即变得非常重要,因为我的行不再是最后一行。
  2. 任何读取文件的进程都可能对该文件的内容有任意要求,而我可能只是破坏了该应用程序。

cha*_*aos 32

只需使用实用程序的 -w标志test

[ -w /path/to/file ] && echo "writeable" || echo "write permission denied"
Run Code Online (Sandbox Code Playgroud)

请注意,如果您稍后要写入该文件,则仍有可能无法写入该文件。文件可能已移动,权限可能已更改等。也可能发生-w检测写入权限但某些其他因素干预使文件不可写的情况

  • @chaos 它既是一个内置的 shell,又是一个外部的可执行文件 - 试试 `type -a` (6认同)
  • [根据源 `test`](http://git.savannah.gnu.org/cgit/coreutils.git/tree/src/test.c#n417) 使用 [`euidaccess` 只检查权限位](http ://coreutils.sourcearchive.com/documentation/8.5/euidaccess-stat_8c-source.html)。是不是还有其他因素(例如 SELinux)会禁止写访问? (2认同)
  • @BroSlow,`&&` 和 `||` 具有相同的优先级。它们是从左到右评估的。 (2认同)

G-M*_*ca' 11

另一种方法:

if >> /path/to/file
then
    echo "writeable"
else
    echo "write permission denied"
fi
Run Code Online (Sandbox Code Playgroud)

这将尝试打开文件进行追加,如果成功, 则不运行任何命令(即,运行空命令)并将输出输出到文件。 

请注意,如果它不存在,这将创建一个空文件。

命令的-w操作员test可能只是执行 astat 然后尝试确定您是否应该具有访问权限。我的替代方案(以上)test在某些特殊情况下比该方法更可靠,因为它强制访问检查由内核而不是外壳程序完成。例如,

  • 如果文件位于非 Unix 文件系统上——特别是如果它是从非 Unix 文件服务器远程挂载的——因为stat可能会返回一个具有误导性的模式值。
  • 如果文件位于以只读方式安装的文件系统上。
  • 如果文件具有 ACL,并且该模式看起来您应该具有访问权限,但 ACL 拒绝访问,反之亦然。
  • 如果某些安全框架(AppArmor、SELinux 等)拒绝访问该文件。

  • 我刚刚测试了这个(在 Debian 上)。时间都没有改变,这就是它应该在任何 Unix 上工作的方式。仅当您从文件中读取时才应更新访问时间,仅当您写入文件时才应更新修改时间。这段代码两者都没有。@Schwern:你的陈述有参考资料吗?你们有人试过吗? (3认同)
  • Champignac 的其他问题:`>> file` 不可移植(例如,在 zsh 中运行 NULLCMD),请改用 `true >> file`。如果文件是命名管道,它会产生令人讨厌的副作用。 (3认同)
  • PS @muru:我只是尝试“触摸”一个我拥有但没有写权限的文件,它成功了。我猜它是`chmod`s 文件,`chmod`s 返回。因此,作为问题的答案,“touch”似乎是绝对无用的。 (2认同)
  • @G-Man 啊,这很有趣。IIRC `vim` 具有在强制写入只读文件时快速更改权限的行为。我检查了`strace`,`touch` 的`open` 失败了`EACCES`,但是随后对`utimensat` 的调用成功,这就是为什么我认为`touch` 整体退出成功。 (2认同)
  • @muru:感谢您检查。`utimensat(2)` 说,“**权限要求:** 1. 写访问(或)2. 调用者的有效用户 ID 必须与文件的所有者相匹配,......” (2认同)