【问题标题】:Can I find out why I can't write to a file in shell script?我可以找出为什么我不能在 shell 脚本中写入文件吗?
【发布时间】:2015-01-24 22:48:40
【问题描述】:

是否有一种编程方式可以找出为什么我无法在 shell 脚本中写入文件(文件存在、访问被拒绝、文件系统已满等)?

例如,在 C 中,为此使用 errno 变量:

FILE *fp = fopen("/etc/passwd", "w");
if (!fp) {
    if (errno == EACCES) {
        // ...
    }
    else if (errno == EEXISTS) {
        // ...
    }
}

我可以用 shell 脚本做类似的事情吗?

我的测试脚本:

#!/bin/sh

err=$(echo 'x' 2>&1 > /etc/passwd)
if [ $? -ne 0 ]; then
    echo "An error occured: $err"
    exit 1
fi

以非 root 用户身份运行此程序将为您提供:

An error occured: 'test.sh: line 3: /etc/passwd: Permission denied'

检查$err 的内容不是恕我直言,这是一个很好的解决方案;错误消息将来可能会发生变化,并且取决于用户的locale 设置。

我也知道我可以在创建文件之前或在退出代码非零之后进行stat 和其他一些检查;但是如果您想检查所有可能的错误,这很快就会失控。在某些情况下,它也容易受到竞争条件的影响(例如在您的 test -f 和实际写入之间创建的文件)。

我正在使用 POSIX shell,并且希望以符合 POSIX 的方式进行,但也可以使用 bashzsh 扩展名。

【问题讨论】:

  • $? 是退出/错误代码。除了您正在捕获的实际字符串输出之外,这就是您将获得的所有内容。

标签: bash shell sh zsh


【解决方案1】:

您的命令将调用的大多数程序都会捕获错误,解释 errno 并打印描述性(但不是机器可读的)错误消息。所以errno的形式信息通常会丢失;您所能做的就是解释人类可读的错误消息。

另一方面,任意命令失败的实际原因取决于智能,除非你想为此编写人工命令,否则你不会成功。如果对文件/a/b/c/d 的写入失败,这可能是因为d 没有设置写入权限位,或者因为abc 中的任何一个都没有执行权限,或者因为存在写入期间出现 I/O 错误,或者因为文件系统以只读方式挂载。而且我确定我只是忘记了更多的可能性。这只是为了对文件进行非常简单的写入。如果您尝试将其直接用于 任意 命令,那就太过分了。

对于单纯的文件访问主题(基于权限),您可以使用faccessat(2) 到达某个地方(但我不知道它的外壳接口)。

【讨论】:

    【解决方案2】:

    有几个操作系统内置函数可以检查文件的特殊功能:

    它存在但你不能写/读它 - 它是 0 字节 - 这是一个目录(!) - 这是一个符号链接 - 还有更多

    通过检查

    man test
    

    或通过以下方式快速检查: http://unixhelp.ed.ac.uk/CGI/man-cgi?test

    此外,您还可以检查文件本身的目录是否存在。这可能是该文件不存在的原因。您可以为此使用 DIRNAME:

    http://linux.die.net/man/1/dirname

    【讨论】:

    • 谢谢;正如我在问题中提到的,这不是我想做的:我也知道我可以在创建文件之前或在退出代码非零之后进行统计和其他一些检查;但是如果您想检查所有可能的错误,这很快就会失控。在某些情况下,它也容易受到竞争条件的影响(例如在您的 test -f 和实际写入之间创建的文件)。
    • 是的,所有这些条件都可能随时发生变化,这也可能需要牢记。文件也可以打开(由进程使用)或不打开。您还可以做一个校验和 (crc/cksum) 来跟踪文件的更改。
    猜你喜欢
    • 2014-09-13
    • 1970-01-01
    • 2019-08-01
    • 2019-11-16
    • 2015-02-23
    • 1970-01-01
    • 1970-01-01
    • 2010-10-05
    相关资源
    最近更新 更多