AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / user-154557

domson's questions

Martin Hope
domson
Asked: 2019-02-18 12:47:57 +0800 CST

来自后台作业的信号陷阱,无需按 Enter

  • 1

在 Bash 5 中,我遇到了我想要执行以下操作的情况:

trap 'echo trapped!' USR1
while true; do kill -SIGUSR1 $$; sleep 1; done &

但是每次发送信号时我都必须在键盘上按 enter 才能使陷阱代码继续。

实际上,我希望在没有任何键盘交互的情况下执行陷阱。

编辑:

最后我让它像这样工作:

trap 'echo trapped!' USR1
while true; do kill -USR1 $$; kill -INT $$; sleep 1; done &

但我认为解决方案是解决方法,而不是答案。

bash shell-script
  • 1 个回答
  • 422 Views
Martin Hope
domson
Asked: 2019-02-16 07:06:54 +0800 CST

如何从函数发出“全局”bash范围内的陷阱?

  • 2

我想在“全局”范围内执行陷阱命令,但信号将来自函数内部。当然,可以预先全局声明变量或使用-gdeclare 选项。但是如果我想在陷阱上获取资源,这不是很实用,如下所示:

#!/bin/bash
# ./variables
declare say=hello
declare -i times=4

和实际的脚本:

#!/bin/bash
# ./trapsource

setTraps () {
  trap 'echo trap called in scope ${FUNCNAME[@]}; source ./variables' SIGUSR1
}

sourceVariables () {
  kill -SIGUSR1 $$
}

setTraps
sourceVariables
echo I want you to $say \"hello\" $times times.
printf "$say\n%.0s" $(seq 1 $times)

但是没有declare -g NAME,谢谢。

编辑:

是否可以将kill -s USR1 $$部件完全从当前过程中分离出来,以便信号来自“外部”?

到目前为止,我尝试过nohup但没有成功。disown

PS:@LL2 在这里提供了一个使用后台进程或 coproc 的解决方案:https ://unix.stackexchange.com/a/518720/154557 但我担心时间同步问题会弹出并使代码不成比例地复杂化。

PPS:实际上@LL2 解决方案甚至适用于 IPC,所以我认为问题已解决。一个缺点是,如果需要在主范围内进一步使用,必须在源文件中处理函数参数,因为子shell中的符号当然会丢失。查看EDIT 2以获取解决此问题的另一种解决方案。

#!/bin/bash
# ./trapsource
set -x  # <-- set debugging to see what happens

setTraps () {
  trap 'declare IPC=./ipc.fifo; \
    [ -p $IPC ] \
    && exec {IPCFD}<>$IPC \
    && { read -a ARGS <&$IPCFD; eval "exec $IPCFD>&-"; } \
    && source "${ARGS[@]}" \
    && IPC_RCV=true' SIGUSR1
}

sourceVariables () {
  declare IPC=./ipc.fifo
  declare IPC_RCV=false
  [ ! -p $IPC ] \
  && mkfifo $IPC
  [ $# -gt 0 ] \
  && exec {IPCFD}<>$IPC \
  && echo "${@:2}" >&$IPCFD \
  && eval "exec $IPCFD>&-" \
  && kill -s USR1 $1
}

test () {
  sourceVariables "$@" &
}

setTraps
test $$ ./variables a b c
while ! [ $say ] ; do :; done  # <-- careful: cpu-intensive loop, only for 
demonstration
echo I want you to $say \"hello\" $times times.
printf "$say\n%.0s" $(seq 1 $times)
printf "'%s' " "${args[@]}"

编辑 2(提案 3 正在进行中):

有没有人有足够的 bash 自定义内置函数经验来指出可以实现真正解决方案的方向?

PS:Bash Loadable Builtins 非常强大,很可能用于接收主范围内的 dbus 方法调用。

解决方案二(没有 bg 也没有 coproc):

看起来信号总是在当前执行行的范围内触发。很可能还有另一种更复杂的解决方案,使用自定义 bash 内置函数(非常强大的可加载内置函数)。我什至可以想到 IPC 的 bash-dbus-builtins。无论如何,如果一个人想告诉自己/另一个在后台休眠的 PID 在信号源上获取一些脚本,而不必在源脚本 ./variables 中设置 -g 全局标志,则使用别名的这种解决方案可能很有用,所以 ./变量脚本也可以在必要时在函数范围内独占使用。由于无法将别名导出到子shell,因此必须将别名包含在 BASH_ENV 变量引用的环境脚本中。在这里,我使用 IPC 机制扩展了原始示例,以使用例的目标更加清晰。

变量存储现在也接收参数

#!/bin/bash
# ./variables
declare say=hello
declare -i times=4
declare -a args=("$@")

首先我准备一个环境脚本

#!/bin/bash
# ./env
shopt -s expand_aliases
alias source_ipc='source ./ipc'
alias source_ipc_rcv='source ./ipc_rcv'

并确保在每个 bash 脚本中都可以使用别名。

$> export BASH_ENV=./env

此外,我需要使用 fifo 的实际 IPC 发送和接收机制

#!/bin/bash
# ./ipc

declare IPC=./ipc.fifo
declare IPC_RCV=false
[ ! -p $IPC ] \
&& mkfifo $IPC
[ $# -gt 0 ] \
&& exec {IPCFD}<>$IPC \
&& echo "${@:2}" >&$IPCFD \
&& eval "exec $IPCFD>&-" \
&& kill -s USR1 $1

加上ipc接收

#!/bin/bash
# ./ipc_rcv

declare IPC=./ipc.fifo
[ -p $IPC ] \
&& exec {IPCFD}<>$IPC \
&& { read -a ARGS <&$IPCFD; eval "exec $IPCFD>&-"; } \
&& source "${ARGS[@]}" \
&& IPC_RCV=true

现在我可以跨多个进程透明地触发源信号

#!/bin/bash
# ./trapsource u+x

trap 'source_ipc_rcv' SIGUSR1

log="$0.log"
err="$0.err.log"
exec 1>$log
exec 2>$err

# test inside script
source_ipc $$ ./variables a b c

while true; do
  echo I want you to \"$say\" $times times.
  if $IPC_RCV; then
    printf "$say\n%.0s" $(seq 1 $times)
    printf "'%s' " "${args[@]}"
  fi
  sleep 1
done

从进程名称空间的“外部”可以按如下方式触发信号。我假设别名已经是 BASH_ENV 参考的来源。

$> ./trapsource & TSPID=$!; sleep 1; source_ipc $TSPID ./variables arg1 arg2; sleep 2; kill $TSPID
bash signals
  • 3 个回答
  • 1689 Views

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve