Bash 如果当前目录没有';不存在?
我如何在Bash脚本中检测当前目录是否不存在,并以“您的当前目录不存在!”这样的消息彻底失败 那么,我如何编写一个在下面的示例中工作的脚本呢Bash 如果当前目录没有';不存在?,bash,Bash,我如何在Bash脚本中检测当前目录是否不存在,并以“您的当前目录不存在!”这样的消息彻底失败 那么,我如何编写一个在下面的示例中工作的脚本呢 $ mkdir /tmp/wow $ cd /tmp/wow $ pwd /tmp/wow $ rm -fr /tmp/wow $ my_script.sh Your current directory doesn't exist! 不可移植答案 (这取决于标准的UNIX文件系统实现细节——没有什么太可怕或不可移植的地方——还取决于文件系统的stat(2
$ mkdir /tmp/wow
$ cd /tmp/wow
$ pwd
/tmp/wow
$ rm -fr /tmp/wow
$ my_script.sh
Your current directory doesn't exist!
不可移植答案
(这取决于标准的UNIX文件系统实现细节——没有什么太可怕或不可移植的地方——还取决于文件系统的stat(2)
系统调用系列的具体实现;因此,这里有龙)
每个inode,包括目录的inode,都保留一个“链接计数”——对它的引用数。对于文件,这表示硬链接的数量;对于目录,来自父目录的链接是1,
目录是另一个,来自任何子目录的。
添加第三个或更高版本。(如果目录是/
,当然,没有来自父目录的链接)
如果文件系统正确地使用这种记帐,stat数据将反映链接的数量。因此:
#!/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的链接计数
便携式回答 缩略形式 虽然可以取消当前目录的链接(也就是说,没有从父目录到当前目录的链接,而父目录可以用来从文件系统根目录遍历到当前目录),但当前目录不可能不存在。作为当前目录,即使不存在将目录作为子目录的父目录,也会使其内存引用计数保持在零以上,从而强制目录继续存在 长形(以及多车、破损的工作区) 如果您希望在移动目录时出现误报: 这就是说,当一个新的和不同的目录被创建时,旧的目录就被创建了,这并没有检测到这种情况。为了处理这个问题,我们可以添加一些额外的逻辑,如下所示:
# 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(和任何其他软件)不再在其中,因为在此之前,它的内存引用计数不是0
因此,当
[-d.]
告诉您您的目录仍然存在时,即使它已被删除。。。这是真的!您的目录仍然存在,因为您的shell当前在其中,这一事实迫使它继续存在。通常一个测试目录(任何目录,包括当前工作目录)是否存在只是为了方便:
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
尝试写入目录时,该目录也不存在,即使出现另一个进程并给出相同的路径名(因为索引节点不同)。如果要检查是否删除了当前目录,请尝试以下操作:
# 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
#首先获取当前目录的inode编号,例如117002
ls-ial | grep'\s\.$| awk'{print$1}'
#然后尝试在父目录中查找inode的路径。如果没有,则删除原始目录
找到-因努姆117002
警告:如果您需要处理重命名,那么您就有问题了。在目录中,它本身增加了它的引用计数,因此意味着它没有被真正删除,即使它不是从任何父目录中都无法访问的。我假设my_script.sh
实际上生活在/tmp/wow
?@chepner-是的,它生活在我的~/bin/
文件夹中…实际上——有一个更好的答案,但它是特定于平台的。我们只能在这里玩Linux吗?嘿!谢谢你的想法!我已经试过了,但还是失败了。这是我尝试运行您建议的shell init:error检索当前目录:getcwd:无法访问父目录:没有这样的文件或目录您的当前目录不存在代码>是的--这些消息是在安装过程中在脚本实际启动之前生成的,因此您对此无能为力。@BradParks,…也就是说,除了最后的之外,您当前的目录不存在代码>,这些消息只是stderr上的警告——它们实际上并没有修改行为或脚本输出(在正式意义上是“写入stdout的内容”)。退出状态是我的命令中的exit
给出的状态。如果您尝试将退出1
修改为,比如说,退出5
,并在运行脚本后选中$?
,您会发现情况确实如此。Hmmm。。。我明白了。。。。如果我只是编辑我的脚本,只需echo hi
,这就行了,但只要我尝试在脚本中使用$PWD
或PWD
,它就会像上面那样消失。如果有一个棘手的方法来找到PWD,那么我可能可以对它做一个不同的检查…再一次,它“像上面一样消亡”,因为我给你的代码使它消亡,因为这是我认为你想要的<代码>echo$PWD
本身会向stderr发出一些警告,但它仍然会打印上次存在的工作目录,并且不会导致任何类型的死亡。啊——编辑后,这不再容易出现问题(您的mv“$home”“$home.backup”
案例涵盖了它)。(这里有一个警告,“现有但不可写”可以混为一谈