如果当前目录不存在,如何使我的Bash脚本失败?

时间:2017-02-07 18:32:51

标签: bash

如何在Bash脚本中检测当前目录是否存在,并且干净地失败并显示“您当前目录不存在!”之类的消息。 ?

那么如何编写一个可以在以下示例中使用的脚本?

$ mkdir /tmp/wow
$ cd /tmp/wow
$ pwd
/tmp/wow
$ rm -fr /tmp/wow
$ my_script.sh
Your current directory doesn't exist!

3 个答案:

答案 0 :(得分:5)

非便携式答案

(这取决于标准的UNIX文件系统实现细节 - 没有什么太可怕或不可移植 - 但也有关于文件系统的stat(2)系列调用的具体实现;因此,这里有龙)。

每个inode(包括目录的inode)都保留“链接计数” - 对它的引用数。对于文件,这表示硬链接的数量;对于目录,来自父级的链接为1,.目录是另一个,并且来自任何子目录的..添加第三个或更晚的目录。 (如果目录是/,当然,没有父母的链接。

如果文件系统正确使用此记帐,则统计数据将反映链接的数量。因此:

#!/bin/bash
link_count=$(stat --format=%h .)    ## --format=%h requires GNU stat
if (( link_count == 0 )); then      ## 0 works w/ ext* on Linux, not guaranteed elsewhere
  echo "This directory has been deleted! Voluntarily exiting" >&2
  exit 1
fi

然而,并非所有操作系统都正确地公开了此会计。例如,对于MacOS上的HFS文件系统,即使目录与其父项取消链接,目录也不会显示小于2的链接数(因此只能通过内存中的引用计数存在 - 如下所述)。 / p>

便携式答案

简短表格

虽然您的当前目录可以取消链接(也就是说,没有从父目录链接到它,可以用来从文件系统根目录遍历它),您目前的目录不存在是不可能的。作为当前目录强制目录继续存在,因为它的内存引用计数保持在零以上,即使没有父目录将其作为子目录。

长形式(和马车,破损的解决方法)

如果您在移动目录时愿意出现误报:

#!/bin/sh
[ -d "$PWD" ] || { echo "Your current directory doesn't exist!" >&2; exit 1; }

也就是说,当你创建一个新的和不同的目录时,这并没有检测到这种情况。为了解决这个问题,我们可能会添加一些额外的逻辑,如下所示:

# perl isn't *truly* portable, in the POSIX-specified sense, but it's everywhere.
ino() { perl -e '@s=stat($ARGV[0]); printf("%s %s\n", $s[0], $s[1]);' "$@"; }
cur_ino=$(ino .)
pwd_ino=$(ino "$PWD")
if [ "$cur_ino" != "$pwd_ino" ]; then
  echo "Directory has been replaced! Following..." >&2
  cd "$PWD" || exit
fi

但是,与任何其他文件一样,在目录上使用开放句柄会阻止它被删除。因此,您的示例中的rm -rf /tmp/wow并未真正删除目录,直到您的shell(和任何其他软件)不再存在,因为在此之前,它的内存中引用count不是0.

因此,当[ -d . ]告诉您目录仍然存在时,即使它已被删除...这实际上是真的!您的目录 仍然存在,因为您的shell当前在其中的事实迫使它继续存在。

答案 1 :(得分:2)

通常会测试目录(任何目录,包括当前工作目录)是否只是为了方便:

  1. 创建缺少的目录(mkdir -p
  2. 存储文件(mktemptouch等)
  3. 这是最后一种情况,可能用于检测您当前的工作目录(.)是否可用:

    function cwd_exists() {
        local fn
        local rc
        fn=$(TMPDIR=. mktemp 2>/dev/null)
        rc=$?
        [ -e "$fn" ] && rm -f "$fn"
        return $rc;
    }
    

    插入演示脚本:

    home=$(mktemp -d)
    cd "$home"
    cwd_exists && echo 'Exists' || echo 'Gone'
    mv "$home" "$home.backup"
    cwd_exists && echo 'Exists' || echo 'Gone'
    mv "$home.backup" "$home"
    cwd_exists && echo 'Exists' || echo 'Gone'
    rm -rf "$home"
    cwd_exists && echo 'Exists' || echo 'Gone'
    mkdir "$home"
    cwd_exists && echo 'Exists' || echo 'Gone'
    

    将回应我认为理想的行为:

    Exists
    Exists
    Exists
    Gone
    Gone
    

    即使目录存在(由于您的脚本保持打开状态),当mktemp尝试写入目录时,该目录也不存在,即使另一个进程出现并提供相同的路径名(因为inode是不同的。)

答案 2 :(得分:1)

如果要检查当前目录是否被删除,请尝试以下操作:

# First get the inode number of current dir, e.g. 117002
ls -ial | grep '\s\.$' | awk '{print $1}'

# Then try to find the inode's path in parent dir. If none, then the original dir was deleted
find .. -inum 117002