`inotifywait`在bash脚本中没有用`-e delete_self`终止;但在交互式shell中却终止了。

问题描述 投票:1回答:1

我想写一个脚本来重新启动一个 python3 -m http.server 进程中,当某个目录(_site)被删除,然后重新创建。 脚本如下。 有一个inotify命令在 waitdel 函数,它应该只阻塞到目录被删除。 当它被删除后,执行过程中会进行简单的轮询等待,直到目录被创建,然后服务器重启,最后我们又回到了等待的状态。

问题是,当 _site 被删除。inotifywait 从未在shell脚本中退出,即使同样的命令 是否 当我在同一个bash提示符下运行这个脚本时,都会退出。DELETEDELETE_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 $0: error: $@
    exit 2
}

say () {
    echo $0 \[$(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
bash inotify inotifywait
1个回答
0
投票

根据@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),inotify wait 是否 成功终止。在(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
}

现在它跟踪DELETE事件 $DIR/..,并对每一个,检查是否 $DIR 被删除。 当它被删除时,它将等待目录被重新生成,然后执行 serve 杀死现有的 python 进程,并生成一个新的进程。

© www.soinside.com 2019 - 2024. All rights reserved.