如何在Bash脚本中检测当前目录不存在,并以像“您的当前目录不存在!”这样的信息干净地失败?
那么我该如何编写以下示例中有效的脚本?
$ mkdir /tmp/wow
$ cd /tmp/wow
$ pwd
/tmp/wow
$ rm -fr /tmp/wow
$ my_script.sh
Your current directory doesn't exist!
如何在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)
系统调用的具体实现方式;因此,请注意以下内容。
每个inode,包括目录inode在内,都有一个“链接计数”(link count)——它的引用次数。对于文件,这代表硬链接的数量;对于目录,来自父目录的链接为1,.
目录是另一个链接,而任何子目录中的..
都会增加第三个及以上的链接数。(如果一个目录是/
,当然没有父链接)。
如果一个文件系统正确使用了这种计数方法,那么stat
命令返回的数据将反映出该inode的链接数。因此:
#!/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
虽然你当前的目录可能是“未链接”的(也就是说,没有来自可以从文件系统根遍历到它的父目录的链接),但它不可能“不存在”。作为你的当前目录,它通过保持其内存中的引用计数大于零而强制一个目录继续存在,即使不存在任何将其作为子目录的父目录。
如果你愿意在目录被“移动”时出现误报:
#!/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
shell-init: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory Your current directory doesn't exist!
- Brad Parksecho hi
,那么它可以工作,但是一旦我尝试在脚本中使用$PWD
或pwd
,它就像上面那样死掉了。如果有一种巧妙的方法来查找PWD,那么我可能可以对其进行不同的检查... - Brad Parksecho $PWD
会向stderr抛出一些警告,但它仍然会打印最后存在的工作目录,并且不会导致任何形式的死亡。 - Charles Duffy$PWD
-- 只有可移植解决方案才会。话虽如此,通过比较 stat
数据,我们确实可以做到这一点。 - Charles Duffymkdir -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不同)。
mv "$home" "$home.backup"
情况已经覆盖了它)。 - Charles Duffymktemp -p .
不是有效的用法。然而,使用 GNU mktemp 就可以正常工作了——因此不能在未链接的目录中创建新内容的规则仍然适用。 - Charles Duffy$PWD
问题,我在我的编辑中解决了这个问题。睡眠有助于缓解疲劳。另外,感谢您的MacOS提示:我已经修复了它以便可移植使用。 - bishop# 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
my_script.sh
实际上存储在/tmp/wow
以外的某个地方? - chepner~/bin/
文件夹中... - Brad Parks