`inotifywait` 不会在带有 `-e delete_self` 的 bash 脚本中终止;但在互动中 shell
`inotifywait` does not terminate in bash script with `-e delete_self`; but does in interactive shell
我正在尝试编写一个脚本,当某个目录 (_site
) 被删除并重新创建时,该脚本会重新启动 python3 -m http.server
进程。脚本如下。 waitdel
函数中有一个 inotify 命令,它应该只阻塞直到目录被删除。当它被删除时,执行继续进行一个简单的轮询等待,直到目录被创建,然后服务器重新启动,最后我们回到等待。
问题是,当 _site
被删除时,inotifywait
永远不会在 shell 脚本中退出,即使完全相同的命令 执行 当我 运行 它在相同的 bash 提示时退出我 运行 这个脚本,在 DELETE
和 DELETE_SELF
.
我已验证正确的 inotifywait
命令是 运行,并且服务器进程没有阻止脚本的执行。那么,为什么它没有在脚本中退出?
#!/usr/bin/env bash
# serve.bash --- serve content, respawn server when _site/ is deleted
# bash strict mode
set -euo pipefail
IFS=$'\n\t'
PID=0
DIR="$PWD/_site" # NO FOLLOWING SLASH OR BREAKS INOTIFYWAIT
PIDFILE="$PWD/.server.pid"
die () {
echo [=13=]: error: $@
exit 2
}
say () {
echo [=13=] \[$(date)\]: $@
}
serve () {
cleanup
old="$PWD"
cd "$DIR" || die Could not cd to "$DIR"
python3 -m http.server 8000 --bind 127.0.0.1 2>&1 &
echo $! > "$PIDFILE"
cd "$old"
}
waitdel () {
while true; do
say Set up watcher for "$DIR"...
inotifywait -e delete_self "$DIR"
say "$DIR" deleted, restarting server...
# Wait&poll till the directory is recreated.
while [ ! -e "$DIR" ]; do
sleep 0.1
done
serve
done
}
cleanup () {
if [[ ! -e "$PIDFILE" ]]; then
return
fi
sync
PID="$(cat $PIDFILE)" && rm "$PIDFILE"
say Kill pid="$PID"...
[ "0" = "$PID" ] || kill -9 "$PID" \
|| die Failed to kill preexisting server on pid "$PID"
}
trap cleanup SIGINT SIGTERM EXIT
if [ -e "$PIDFILE" ]; then
if pgrep -a python3 | grep http\.server >/dev/null; then
trap - SIGINT SIGTERM EXIT
die Stale pidfile found at "$PIDFILE", a potentially orphaned \
server might be running. Please kill it before proceeding.
else
rm "$PIDFILE" # remove stale pidfile when no server proc found
fi
fi
serve
waitdel
根据@oguz ismail 的建议,我已尝试生成可以重现该问题的最小版本的脚本,这里是:
DIR="$PWD/_site"
mkdir -p $DIR
old="$PWD"
cd "$DIR" || die Could not cd to "$DIR"
python3 -m http.server 8000 --bind 127.0.0.1 2>&1 & # (1)
cd "$old"
pid=$!
inotifywait -e delete_self "$DIR" & # (2)
sleep 1
rmdir $DIR
sleep 1
kill $pid
echo kill # (3)
这里发生了什么:通过样板文件,在表达式 (1) 中,我们启动了一个 python http.server 进程,其 CWD 为 $DIR
。如果不是这样,即 CWD 是 $(dirname $DIR)
,inotifywait does 成功终止。在 (3) 中,我们清理服务器进程。如果我们终止 python 进程,inotifywait 终止,如果我们不终止,它也不会终止。过程的输出
Setting up watches.
Watches established.
Serving HTTP on 127.0.0.1 port 8000 (http://127.0.0.1:8000/) ...
kill
/home/g/co/gkayaalp.com/www/_site/ DELETE_SELF
建议 inotifywait 在 (3) 之后终止。
因此inotifywait 挂起是因为$DIR
很忙(我猜是因为inotify 与inode 一起工作,python 进程挂在inode 上,延迟了删除事件的传播)。一种快速的补救方法是改为监视父目录。我将 waitdel
修改为:
waitdel () {
while true; do
say Set up watcher for "$DIR"...
while inotifywait -qq -e delete "$DIR/.."; do
if [ ! -e $DIR ]; then
say "$DIR" deleted, restarting server...
# Wait&poll till the directory is recreated.
while [ ! -e "$DIR" ]; do
sleep 0.1
done
serve
fi
done
done
}
现在它跟踪 $DIR/..
上的 DELETE 事件,并在每个事件上检查 $DIR
是否被删除。如果是,它会等待重新生成目录,然后运行 serve
杀死现有的 python 进程并生成一个新进程。
我正在尝试编写一个脚本,当某个目录 (_site
) 被删除并重新创建时,该脚本会重新启动 python3 -m http.server
进程。脚本如下。 waitdel
函数中有一个 inotify 命令,它应该只阻塞直到目录被删除。当它被删除时,执行继续进行一个简单的轮询等待,直到目录被创建,然后服务器重新启动,最后我们回到等待。
问题是,当 _site
被删除时,inotifywait
永远不会在 shell 脚本中退出,即使完全相同的命令 执行 当我 运行 它在相同的 bash 提示时退出我 运行 这个脚本,在 DELETE
和 DELETE_SELF
.
我已验证正确的 inotifywait
命令是 运行,并且服务器进程没有阻止脚本的执行。那么,为什么它没有在脚本中退出?
#!/usr/bin/env bash
# serve.bash --- serve content, respawn server when _site/ is deleted
# bash strict mode
set -euo pipefail
IFS=$'\n\t'
PID=0
DIR="$PWD/_site" # NO FOLLOWING SLASH OR BREAKS INOTIFYWAIT
PIDFILE="$PWD/.server.pid"
die () {
echo [=13=]: error: $@
exit 2
}
say () {
echo [=13=] \[$(date)\]: $@
}
serve () {
cleanup
old="$PWD"
cd "$DIR" || die Could not cd to "$DIR"
python3 -m http.server 8000 --bind 127.0.0.1 2>&1 &
echo $! > "$PIDFILE"
cd "$old"
}
waitdel () {
while true; do
say Set up watcher for "$DIR"...
inotifywait -e delete_self "$DIR"
say "$DIR" deleted, restarting server...
# Wait&poll till the directory is recreated.
while [ ! -e "$DIR" ]; do
sleep 0.1
done
serve
done
}
cleanup () {
if [[ ! -e "$PIDFILE" ]]; then
return
fi
sync
PID="$(cat $PIDFILE)" && rm "$PIDFILE"
say Kill pid="$PID"...
[ "0" = "$PID" ] || kill -9 "$PID" \
|| die Failed to kill preexisting server on pid "$PID"
}
trap cleanup SIGINT SIGTERM EXIT
if [ -e "$PIDFILE" ]; then
if pgrep -a python3 | grep http\.server >/dev/null; then
trap - SIGINT SIGTERM EXIT
die Stale pidfile found at "$PIDFILE", a potentially orphaned \
server might be running. Please kill it before proceeding.
else
rm "$PIDFILE" # remove stale pidfile when no server proc found
fi
fi
serve
waitdel
根据@oguz ismail 的建议,我已尝试生成可以重现该问题的最小版本的脚本,这里是:
DIR="$PWD/_site"
mkdir -p $DIR
old="$PWD"
cd "$DIR" || die Could not cd to "$DIR"
python3 -m http.server 8000 --bind 127.0.0.1 2>&1 & # (1)
cd "$old"
pid=$!
inotifywait -e delete_self "$DIR" & # (2)
sleep 1
rmdir $DIR
sleep 1
kill $pid
echo kill # (3)
这里发生了什么:通过样板文件,在表达式 (1) 中,我们启动了一个 python http.server 进程,其 CWD 为 $DIR
。如果不是这样,即 CWD 是 $(dirname $DIR)
,inotifywait does 成功终止。在 (3) 中,我们清理服务器进程。如果我们终止 python 进程,inotifywait 终止,如果我们不终止,它也不会终止。过程的输出
Setting up watches.
Watches established.
Serving HTTP on 127.0.0.1 port 8000 (http://127.0.0.1:8000/) ...
kill
/home/g/co/gkayaalp.com/www/_site/ DELETE_SELF
建议 inotifywait 在 (3) 之后终止。
因此inotifywait 挂起是因为$DIR
很忙(我猜是因为inotify 与inode 一起工作,python 进程挂在inode 上,延迟了删除事件的传播)。一种快速的补救方法是改为监视父目录。我将 waitdel
修改为:
waitdel () {
while true; do
say Set up watcher for "$DIR"...
while inotifywait -qq -e delete "$DIR/.."; do
if [ ! -e $DIR ]; then
say "$DIR" deleted, restarting server...
# Wait&poll till the directory is recreated.
while [ ! -e "$DIR" ]; do
sleep 0.1
done
serve
fi
done
done
}
现在它跟踪 $DIR/..
上的 DELETE 事件,并在每个事件上检查 $DIR
是否被删除。如果是,它会等待重新生成目录,然后运行 serve
杀死现有的 python 进程并生成一个新进程。