我需要为后台启动的bash进程设置一个陷阱.后台进程可能运行很长时间并将其PID保存在特定文件中.
现在我需要为该进程设置一个陷阱,所以如果它终止,PID文件将被删除.
有没有办法可以做到这一点?
看起来我对问题的描述看起来不够精确.我可以完全控制所有代码,但我拥有的长时间运行后台进程是这样的:
cat /dev/random >> myfile&
Run Code Online (Sandbox Code Playgroud)
当我现在在脚本的开头添加陷阱时,这个语句就在,$$将是那个更大的脚本的PID而不是我从这里开始的这个小后台进程.
那么如何具体为后台进程设置陷阱呢?
我正在编写一个bash脚本,它会产生许多后台进程.我想在进程终止时收到通知; 我想知道终止过程的pid.
我已经看过使用wait,这样每个衍生进程的pid都被捕获并存储在一个数组中,然后遍历数组,并在每个进程上调用wait.这里以各种方式描述了这种技术:
如果我理解正确的话,问题在于,如果您希望在单个进程终止后立即执行某些操作,则效率相对较低.例如,如果您生成进程A和B,并且B在A之前完成,则执行必须等待A和B完成.B完成后我需要立即执行操作.
trap SIGCHLD当孩子终止时,似乎是立即执行操作的方法,但问题是我找不到确定SIGCHLD信号源的pid的方法,这也是我需要的.我发现的最接近的一个例子就是这篇文章中的第三个代码示例:
http://www.linuxforums.org/forum/programming-scripting/103996-multithreading-bash.html#post510187
为方便起见,我在这里复制粘贴:
#!/bin/bash
iNext=0
function ChildReturned() {
wait $1
echo "$1 was returned. Its exits status was: $?"
iNext=$((iNext+1))
StartChild $iNext
}
function StartChild {
./child $1 &
pid=$!
echo "Started: $1 PID= $pid"
trap 'ChildReturned $pid' SIGCHLD
}
set -bm
for (( iNext=0; iNext<=10; iNext++ ));
do
StartChild $iNext
done
wait
Run Code Online (Sandbox Code Playgroud)
我认为这个例子不起作用,因为作者犯了trap多次调用的错误,每次都在trap's参数中捕获一个不同的pid变量.每次调用陷阱时,它都会覆盖先前的调用,因此将捕获任意pid.我找不到更好的技术.
有没有办法在bash中使用陷阱获取已终止子进程的pid?
更新
我只想指出这个资源,其中包含迄今为止我所看到的解决此问题的最佳,最全面的概述:
我正在为应用程序编写一个bash包装器.该包装器负责更改用户,运行软件和记录其输出.我也希望它传播SIGINT信号.
到目前为止,这是我的代码:
#!/bin/bash
set -e; set -u
function child_of {
ps --ppid $1 -o "pid" --no-headers | head -n1
}
function handle_int {
echo "Received SIGINT"
kill -int $(child_of $SU_PID)
}
su myuser -p -c "bash /opt/loop.sh 2>&1 | tee -i >(logger -t mytag)" &
SU_PID=$!
trap "handle_int" SIGINT
wait $SU_PID
echo "This is the end."
Run Code Online (Sandbox Code Playgroud)
我的问题是,当我向这个包装器发送一个SIGINT时,handle_int会被调用但是脚本结束了,而我希望它继续等待$SU_PID.
有没有办法捕获int信号,做一些事情,然后阻止脚本终止?
我正在尝试在我的脚本中获取 SIGSTOP CTRL+信号。Ztrap
当我的脚本正在执行时,如果我暂时暂停执行,发送 SIGSTOP 信号CTRL+ Z,它需要删除我在其中创建的文件并终止执行。
我不明白为什么下面的脚本不起作用。但更重要的是,正确的做法是什么?
#!/bin/bash
DIR="temp_folder"
trap "rm -r $DIR; kill -SIGINT $$" SIGSTP
if [ -d $DIR ]
then
rm -r $DIR
else
mkdir $DIR
fi
sleep 5
Run Code Online (Sandbox Code Playgroud)
编辑:
SIGSTOP不能被捕获,但是SIGTSTP可以被捕获,根据我在互联网上搜索CTRL和下面的答案后的理解,用+发送信号时捕获是正确的Z。但是,当我在运行脚本时按CTRL+时,它将被卡住,这意味着无论我之后发送什么信号,脚本都会无限执行。
Z
trap由于这个问题,我正在玩一个函数内部,并提出了这个次要问题.给出以下代码:
d() {
trap 'return' ERR
false
echo hi
}
Run Code Online (Sandbox Code Playgroud)
如果我运行d,trap导致shell从函数返回而不打印'hi'.到现在为止还挺好.但如果我第二次运行它,我会收到来自shell的消息:
-bash:return:只能从函数或源脚本"返回"
起初,我认为这意味着ERR sig发生了两次:一次当false给出非零退出状态(在函数内部)时,再次当函数本身返回非零退出状态(在函数外部)时.但是这个假设并没有阻止这个测试:
e() {
trap 'echo +;return' ERR
false
echo hi
}
Run Code Online (Sandbox Code Playgroud)
如果我运行上面,无论我怎么经常运行它,我不再让不仅可以return从函数或执行的脚本由bash的警告.为什么shell处理的复合命令与traparg中的简单命令不同?
我的目标是维护导致函数退出的命令的实际退出状态,但我认为导致上述行为的任何因素也会导致捕获退出状态变得复杂:
f() {
trap '
local s=$?
echo $s
return $s' ERR
false
echo hi
}
bash> f; echo $?
1
0
Run Code Online (Sandbox Code Playgroud)
笏?有人可以解释为什么$s在这里扩展到两个不同的值,如果事实证明是相同的原因,上面的区别return和echo +; return?
我有一个脚本,其内部结构可归结为:
trap "exit" SIGINT SIGTERM
while :
do
mplayer sound.mp3
sleep 3
done
Run Code Online (Sandbox Code Playgroud)
(是的,这是比上面更有意义一点,但是这是不相关的问题)。脚本的多个实例可能同时运行。
有时我想 ^C 脚本......但这不会成功。据我了解,当 ^C 杀死时mplayer,它会继续sleep,当 ^C 杀死时sleep,它会继续mplayer,而且我从未碰巧在两者之间抓住它。据我了解,trap永远不会奏效。
如何终止脚本?
对于 Bash 程序:
1 #!/bin/bash
2
3 trapinfo()
4 {
5 echo "=== Trap Info: Status=$? LINENO=$@ A=$A"
6 }
7
8 main()
9 {
10 trap 'trapinfo $LINENO -- ${BASH_LINENO[*]}' ERR
11
12 set -e
13 set -E
14 set -o errtrace
15 shopt -s extdebug
16
17 local -g A=1
18
19 # false # If uncommented, LINENO would be 19
20 (exit 73) # LINENO is 9. How can I get 20 instead?
21
22 A=2
23 …Run Code Online (Sandbox Code Playgroud) 在bash函数中声明局部变量使该变量仅在函数本身及其子级内部可见,因此如果我运行:
#!/bin/bash
set -e
func_one() {
echo "${var}"
}
func_two() {
local -r var="var from func_two"
func_one
}
func_two
Run Code Online (Sandbox Code Playgroud)
输出为:
var from func_two
Run Code Online (Sandbox Code Playgroud)
即使var变量声明为local,并且func_two内的只读变量也可以从func_one函数访问。在后者中,可以声明一个具有本地和只读名称的变量:
#!/bin/bash
set -e
func_one() {
local -r var="var from func_one"
echo "${var}"
}
func_two() {
local -r var="var from func_two"
func_one
}
func_two
Run Code Online (Sandbox Code Playgroud)
输出为:
var from func_one
Run Code Online (Sandbox Code Playgroud)
如果从EXIT陷阱调用func_one,也会发生同样的情况:
#!/bin/bash
set -e
func_one() {
local -r var="var from func_one"
echo "${var}"
}
func_two() {
local …Run Code Online (Sandbox Code Playgroud) 我有一个 docker 入口点脚本,该脚本应该捕获发送到容器中进程的信号。主要应用程序是 tomcat - 嵌入在 docker-entrypoint.sh 中的 java 进程,该进程被传递给 dumb-init。容器中的流程映射如下所示:
root@mycontainer:/usr/local/tomcat/webapps/datarouter-example# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 05:21 ? 00:00:00 dumb-init -- /docker-entrypoint.sh
root 6 1 0 05:21 ? 00:00:00 bash /docker-entrypoint.sh
root 14 6 1 05:21 ? 00:08:57 /jdk-13.0.1/bin/java -Djava.util.logging.config.file=....
Run Code Online (Sandbox Code Playgroud)
Dockerfile:
FROM maven:3.6.3-jdk-13 as maven_builder
WORKDIR /app
COPY . /app
RUN ["mvn","clean","install","-T","2C","-DskipTests=true"]
FROM tomcat:9.0.31-jdk13-openjdk-buster
ARG dumbInitVersion='1.2.2'
# install dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
sudo \ …Run Code Online (Sandbox Code Playgroud) 我正在编写一个 shell 脚本,它定期执行任务并从另一个进程接收到 USR1 信号。
脚本的结构类似于这个答案:
#!/bin/bash
trap 'echo "doing some work"' SIGUSR1
while :
do
sleep 10 && echo "doing some work" &
wait $!
done
Run Code Online (Sandbox Code Playgroud)
但是,此脚本存在睡眠过程在后台继续并且仅在超时时终止的问题。(请注意,当在等待期间收到 USR1 时,睡眠进程会在其常规超时期间徘徊,但周期性回声确实被取消。)例如,您可以使用pkill -0 -c sleep.
我读了这个页面,它建议在陷阱动作中杀死挥之不去的睡眠,例如
#!/bin/bash
pid=
trap '[[ $pid ]] && kill $pid; echo "doing some work"' SIGUSR1
while :
do
sleep 10 && echo "doing some work" &
pid=$!
wait $pid
pid=
done
Run Code Online (Sandbox Code Playgroud)
但是,如果我们快速向 USR1 信号发送垃圾邮件,则此脚本会出现竞争条件,例如:
pkill -USR1 trap-test.sh; pkill -USR1 trap-test.sh
Run Code Online (Sandbox Code Playgroud)
然后它会尝试杀死一个已经被杀死的 …