从子 shell 退出整个 bash 脚本
Exiting entire bash script from subshell
我对 bash 脚本有点陌生,我有一个 C++ 程序通过一些命名管道与这个 bash 脚本来回通信。我使用 inotifywait 来监视文件夹中的新文件,并在添加新文件(以 .job 结尾)时通过管道将其发送。
我正在让 C++ 程序返回结果,如果结果是 'quit',我想 bash 脚本退出执行。
我试图通过出口 1 完成此操作,如下所示,但这似乎并没有退出整个脚本。相反,退出后是 运行,当我将另一个文件放入监视文件夹时,脚本结束。
我阅读了一些关于子 shell 的内容,想知道这是否与它们有关,以及关于如何退出整个脚本的任何建议。
DROP_FOLDER=""
DATA_FOLDER=""
OUTPUT_FOLDER=""
PATH_TO_EXECS="./tmp/"
PATH_TO_COMPLETED="../completed/"
# create pipes
read_pipe=/tmp/c_to_bash
write_pipe=/tmp/bash_to_c
if [[ ! -p $read_pipe ]]; then
mkfifo $read_pipe
fi
if [[ ! -p $write_pipe ]]; then
mkfifo $write_pipe
fi
# start c++ program
./tmp/v2 $DATA_FOLDER $OUTPUT_FOLDER $PATH_TO_EXECS "${write_pipe}" "${read_pipe}" &
# watch drop folder
inotifywait -m $DROP_FOLDER -e create -e moved_to |
while read path action file; do
# ends in .tga
if [[ "$file" =~ .*tga$ ]]; then
# move to image dir
mv "${DROP_FOLDER}${file}" "${DATA_FOLDER}${file}"
fi
# ends in .job
if [[ "$file" =~ .*job$ ]]; then
# pipe to dispatcher
echo "${DROP_FOLDER}${file}" > $write_pipe
# wait for result from pipe
if read line <$read_pipe; then
echo $line
# check for quit result
if [[ "$line" == 'quit' ]]; then
# move job file to completed
mv "${DROP_FOLDER}${file}" "${PATH_TO_COMPLETED}${file}"
# exit
exit 1
fi
# check for continue result
if [[ "$line" == 'continue' ]]; then
# move job file to completed
mv "${DROP_FOLDER}${file}" "${PATH_TO_COMPLETED}${file}"
fi
fi
fi
done
问题是 exit
只退出当前的子 shell,在你的情况下是你的 while 循环由于管道。
Bash 仍在等待 inotifywait
退出,直到它尝试写入另一个值并检测到管道已损坏时才会退出。
要解决这个问题,您可以使用进程替换而不是管道:
while read path action file; do
...
done < <(inotifywait -m $DROP_FOLDER -e create -e moved_to)
这是可行的,因为循环不在子 shell 中执行,因此 exit
语句将退出整个脚本。此外,bash 不会等待进程替换退出,因此虽然它可能会一直等待直到下一次尝试写入,但它不会阻止脚本退出。
通常,您可以使用子shell中的kill "$$"
来终止主脚本($$
将扩展到主shell的pid即使在 subshells 中,您也可以设置一个 TERM
陷阱以捕获该信号)。
但看起来您实际上想从管道的右侧终止管道的左侧——即导致 inotifywait
终止而不等到它正在向孤立管道写入内容并被 SIGPIPE
。为此,您可以使用 pkill
:
显式终止 inotifywait
进程
inotifywait -m /some/dir -e create,modify |
while read path action file; do
pkill -PIPE -P "$$" -x inotifywait
done
pkill -P
父级选择; $$
应该是您脚本的 PID。这个解决方案当然不是fool-proof。也看看 this.
我对 bash 脚本有点陌生,我有一个 C++ 程序通过一些命名管道与这个 bash 脚本来回通信。我使用 inotifywait 来监视文件夹中的新文件,并在添加新文件(以 .job 结尾)时通过管道将其发送。
我正在让 C++ 程序返回结果,如果结果是 'quit',我想 bash 脚本退出执行。
我试图通过出口 1 完成此操作,如下所示,但这似乎并没有退出整个脚本。相反,退出后是 运行,当我将另一个文件放入监视文件夹时,脚本结束。
我阅读了一些关于子 shell 的内容,想知道这是否与它们有关,以及关于如何退出整个脚本的任何建议。
DROP_FOLDER=""
DATA_FOLDER=""
OUTPUT_FOLDER=""
PATH_TO_EXECS="./tmp/"
PATH_TO_COMPLETED="../completed/"
# create pipes
read_pipe=/tmp/c_to_bash
write_pipe=/tmp/bash_to_c
if [[ ! -p $read_pipe ]]; then
mkfifo $read_pipe
fi
if [[ ! -p $write_pipe ]]; then
mkfifo $write_pipe
fi
# start c++ program
./tmp/v2 $DATA_FOLDER $OUTPUT_FOLDER $PATH_TO_EXECS "${write_pipe}" "${read_pipe}" &
# watch drop folder
inotifywait -m $DROP_FOLDER -e create -e moved_to |
while read path action file; do
# ends in .tga
if [[ "$file" =~ .*tga$ ]]; then
# move to image dir
mv "${DROP_FOLDER}${file}" "${DATA_FOLDER}${file}"
fi
# ends in .job
if [[ "$file" =~ .*job$ ]]; then
# pipe to dispatcher
echo "${DROP_FOLDER}${file}" > $write_pipe
# wait for result from pipe
if read line <$read_pipe; then
echo $line
# check for quit result
if [[ "$line" == 'quit' ]]; then
# move job file to completed
mv "${DROP_FOLDER}${file}" "${PATH_TO_COMPLETED}${file}"
# exit
exit 1
fi
# check for continue result
if [[ "$line" == 'continue' ]]; then
# move job file to completed
mv "${DROP_FOLDER}${file}" "${PATH_TO_COMPLETED}${file}"
fi
fi
fi
done
问题是 exit
只退出当前的子 shell,在你的情况下是你的 while 循环由于管道。
Bash 仍在等待 inotifywait
退出,直到它尝试写入另一个值并检测到管道已损坏时才会退出。
要解决这个问题,您可以使用进程替换而不是管道:
while read path action file; do
...
done < <(inotifywait -m $DROP_FOLDER -e create -e moved_to)
这是可行的,因为循环不在子 shell 中执行,因此 exit
语句将退出整个脚本。此外,bash 不会等待进程替换退出,因此虽然它可能会一直等待直到下一次尝试写入,但它不会阻止脚本退出。
通常,您可以使用子shell中的kill "$$"
来终止主脚本($$
将扩展到主shell的pid即使在 subshells 中,您也可以设置一个 TERM
陷阱以捕获该信号)。
但看起来您实际上想从管道的右侧终止管道的左侧——即导致 inotifywait
终止而不等到它正在向孤立管道写入内容并被 SIGPIPE
。为此,您可以使用 pkill
:
inotifywait
进程
inotifywait -m /some/dir -e create,modify |
while read path action file; do
pkill -PIPE -P "$$" -x inotifywait
done
pkill -P
父级选择; $$
应该是您脚本的 PID。这个解决方案当然不是fool-proof。也看看 this.