标签: bash-trap

在已知PID的不同进程中为bash设置陷阱

我需要为后台启动的bash进程设置一个陷阱.后台进程可能运行很长时间并将其PID保存在特定文件中.

现在我需要为该进程设置一个陷阱,所以如果它终止,PID文件将被删除.

有没有办法可以做到这一点?

编辑#1

看起来我对问题的描述看起来不够精确.我可以完全控制所有代码,但我拥有的长时间运行后台进程是这样​​的:

cat /dev/random >> myfile&
Run Code Online (Sandbox Code Playgroud)

当我现在在脚本的开头添加陷阱时,这个语句就在,$$将是那个更大的脚本的PID而不是我从这里开始的这个小后台进程.

那么如何具体为后台进程设置陷阱呢?

bash pid bash-trap

5
推荐指数
1
解决办法
2579
查看次数

使用bash中的陷阱捕获已终止后台进程的pid

我正在编写一个bash脚本,它会产生许多后台进程.我想在进程终止时收到通知; 我想知道终止过程的pid.

我已经看过使用wait,这样每个衍生进程的pid都被捕获并存储在一个数组中,然后遍历数组,并在每个进程上调用wait.这里以各种方式描述了这种技术:

/sf/answers/24930811/

如果我理解正确的话,问题在于,如果您希望在单个进程终止后立即执行某些操作,则效率相对较低.例如,如果您生成进程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?

更新

我只想指出这个资源,其中包含迄今为止我所看到的解决此问题的最佳,最全面的概述:

http://mywiki.wooledge.org/ProcessManagement#I_want_to_process_a_bunch_of_files_in_parallel.2C_and_when_one_finishes.2C_I_want_to_start_the_next._And_I_want_to_make_sure_there_are_exactly_5_jobs_running_at_a_time.

unix bash signals child-process bash-trap

5
推荐指数
1
解决办法
5799
查看次数

在处理SIGINT后阻止bash脚本终止

我正在为应用程序编写一个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信号,做一些事情,然后阻止脚本终止?

linux bash signals bash-trap

5
推荐指数
1
解决办法
1416
查看次数

Shell 脚本通过 Trap 获取 CTRL+Z

我正在尝试在我的脚本中获取 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在此输入图像描述

linux bash shell signals bash-trap

5
推荐指数
2
解决办法
8403
查看次数

陷阱/返回后退出状态在哪里?

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在这里扩展到两个不同的值,如果事实证明是相同的原因,上面的区别returnecho +; return

bash exit-code bash-trap

5
推荐指数
1
解决办法
1034
查看次数

ctrl+c 使用子进程杀死 bash 脚本

我有一个脚本,其内部结构可归结为:

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永远不会奏效。

如何终止脚本?

linux bash bash-trap

5
推荐指数
1
解决办法
3608
查看次数

Bash 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)

linux bash shell centos7 bash-trap

5
推荐指数
1
解决办法
413
查看次数

程序以状态!= 0(set -e)退出后执行EXIT陷阱时的Bash函数作用域状态

在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)

bash local readonly bash-trap

5
推荐指数
1
解决办法
54
查看次数

无法在 docker 入口点脚本中捕获信号

我有一个 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)

wait sigterm docker bash-trap tomcat9

5
推荐指数
1
解决办法
6156
查看次数

在 USR1 信号后可靠地终止睡眠进程

我正在编写一个 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)

然后它会尝试杀死一个已经被杀死的 …

linux bash shell sleep bash-trap

5
推荐指数
1
解决办法
594
查看次数

标签 统计

bash-trap ×10

bash ×9

linux ×5

shell ×3

signals ×3

centos7 ×1

child-process ×1

docker ×1

exit-code ×1

local ×1

pid ×1

readonly ×1

sigterm ×1

sleep ×1

tomcat9 ×1

unix ×1

wait ×1