如何在Bash脚本中检测当前目录是否存在,并且干净地失败并显示“您当前目录不存在!”之类的消息。 ?
那么如何编写一个可以在以下示例中使用的脚本?
$ mkdir /tmp/wow
$ cd /tmp/wow
$ pwd
/tmp/wow
$ rm -fr /tmp/wow
$ my_script.sh
Your current directory doesn't exist!
答案 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)
通常会测试目录(任何目录,包括当前工作目录)是否只是为了方便:
mkdir -p
)mktemp
,touch
等)这是最后一种情况,可能用于检测您当前的工作目录(.
)是否可用:
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