Shell脚本:Linux Shell脚本学习指南(第三部分Shell高级)四
十九、Linux Shell trap命令:捕获信号
到目前为止,我们在本教程所见的脚本中还没有需要信号处理功能的,因为它们的内容相对比较简单,执行时间很短,而且不会创建临时文件。而对于较大的或者更复杂的脚本来说,如果脚本具有信号处理机制可能就比较有用了。
当我们设计一个大且复杂的脚本时,考虑到当脚本运行时出现用户退出或系统关机会发生什么是很重要的。当这样的事件发生时,一个信号将会发送到所有受影响的进程。相应地,这些进程的程序可以采取一些措施以确保程序正常有序地终结。比如说,我们编写了一个会在执行时生成临时文件的脚本。在好的设计过程中,我们会让脚本在执行完成时删除这些临时文件。同样聪明的做法是,如果脚本接收到了指示程序将提前结束的信号,也应删除这些临时文件。
接下来,就让我们开始学习,如何在脚本中进行这些处理。
trap 命令
Bash Shell 的内部命令 trap 让我们可以在 Shell 脚本内捕获特定的信号并对它们进行处理。 trap 命令的语法如下所示:
trap command signal [ signal ... ]
上述语法中,command 可以是一个脚本或是一个函数。signal 既可以用信号名,也可以用信号值指定。
你可以不指定任何参数,而直接使用 trap 命令,它将会打印与每个要捕获的信号相关联的命令的列表。
当 Shell 收到信号 signal(s) 时,command 将被读取和执行。比如,如果 signal 是 0 或 EXIT 时,command 会在 Shell 退出时被执行。如果 signal 是 DEBUG 时,command 会在每个命令后被执行。
signal 也可以被指定为 ERR,那么每当一个命令以非 0 状态退出时, command 就会被执行(注意,当非 0 退出状态来自一个 if 语句部分,或来自 while、until 循环时,command 不会被执行)。
下面我们通过几个简单的实例来学习 trap 命令的用法。
首先,我们定义一个变量 FILE:
[c.biancheng.net]$ FILE=`mktemp -u /tmp/testtrap.$$.XXXXXX`
这里使用 mktemp 命令创建一个临时文件;使用-u选项,表示并不真正创建文件,只是打印生成的文件名;“XXXXXX”表示生成 6 位随机字符。
然后,我们定义捕获错误信号:
[c.biancheng.net]$ trap "echo There exist some error!" ERR
查看已经定义的捕获:
[c.biancheng.net]$ trap
trap -- 'echo There exist some error!' ERR
此时,当我们尝试使用 rm 命令删除变量 $FILE 代表的并不存在的文件时,就会显示类似如下的错误信息:
[c.biancheng.net]$ rm $FILE
rm: cannot remove '/tmp/testtrap.8020.zafuo4': No such file or directory
There exist some error!
从上面的输出中我们看到,Shell 捕获到了文件 /tmp/testtrap.8020.zafuo4 不存在的这个错误信号,并执行了 echo 命令,显示了我们指定的错误信息。
当调试较大的脚木时,你可能想要赋予某个变量一个踪迹属性,并捕获变量的调试信息。通常,你可能只使用一个简单的赋值语句,比如,VARIABLE=value,来定义一个变量。若使用类似如下的语句替换上述的变量定义,可能会为你提供更有用的调试信息:
#声明变景 VARIABLE,并赋予其踪迹属性
declare -t VARIABLE=value
#捕获DEBUG
trap "echo VARIABLE is being used here." DEBUG
#脚本的余下部分
现在,我们创建一个名称为 testtrap1.sh 的脚本,其内容如下所示:
#!/bin/bash
#捕获退出状态0
trap 'echo "Exit 0 signal detected..."' 0
#打印信息
echo "This script is used for testing trap command."
#以状态(信号)0 退出此 Shell 脚本
exit 0
此脚本运行结果将类似如f所示:
[c.biancheng.net]$ bash ./testtrap1.sh
This script is used for testing trap command.
Exit 0 signal detected...
在上述的脚本中,trap 命令语句设置了一个当脚本以 0 状态退出时的捕获,所以当脚本以 0 状态退出时,会打印一条信息“Exit 0 signal detected...”。
我们再创建一个名称为 testtrap2.sh 的脚本,其内容类似如下所示:
#!/bin/bash
#捕获信号 SIGINT,然后打印相应信息
trap "echo 'You hit control+C! I am ignoring you.'" SIGINT
#捕获信号 SIGTERM,然后打印相应信息
trap "echo 'You tried to kill me! I am ignoring you.'" SIGTERM
#循环5次
for i in {1..5}; do
echo "Iteration $i of 5"
#暂停5秒
sleep 5
done
当你运行上述脚本时,如果敲击 CTRL+C 组合键,将会中断 sleep 命令,进入下一次循环,并看到输出信息 “You hit control+C! I am ignoring you.”,但脚本 testtrap2.sh 并不会停止运行。此脚木的运行结果将类似如下所示:
[c.biancheng.net]$ bash ./testtrap2.sh
Iteration 1 of 5
You hit control+C! I am ignoring you.
Iteration 2 of 5
Iteration 3 of 5
Iteration 4 of 5
You hit control+C! I am ignoring you.
Iteration 5 of 5
当将上述脚本放在后台运行时,如果我们同时在另一个终端窗口尝试使用 kill 命令终结此脚木,此脚本并不会被终结,而是会显示信息“You tried to kill me! I am ignoring you.”, 此脚本的运行结果将会类似如下所示:
[c.biancheng.net]$ sh ./testtrap2.sh &
[1] 2320
[c.biancheng.net]$ Iteration 1 of 5
You tried to kill me! I am ignoring you.
Iteration 2 of 5
Iteration 3 of 5
Iteration 4 of 5
You tried to kill me! I am ignoring you.
Iteration 5 of 5
You tried to kill me! I am ignoring you.
[1]+ Done sh ./testtrap2.sh
有时,接收到一个信号后你可能不想对其做任何处理。比如,当你的脚本处理较大的文件时,你可能希望阻止一些错误地输入 Ctrl+C 或 Ctrl+\ 组合键的做法,并且希望它能执行完成而不被用户中断。这时就可以使用空字符串" "或' '作为 trap 的命令参数,那么 Shell 将忽略这些信号。其用法类似如下所示:
$ trap ' ' SIGHUP SIGINT [ signal... ]
二十、Linux Shell trap命令捕获信号实例演示
通过前面内容的学习,我们已经知道,信号多用于以友好的方式结束一个进程的执行,即允许进程在退出之前有机会做一些清理工作。然而,信号同样还可用于其他用途。例如,当终端窗口的大小改变时,在此窗口中运行的 Shell 都会接收到信号 SIGWINCH。通常,这个信号是被忽略的,但是,如果一个程序关心窗口大小的变化,它就可以捕获这个信号,并用特定的方式处理它。
注意:除 SIGKILL 信号以外,其他任何信号都可以被捕获并通过调用C语言函数 signal 处理。
接下来,我就以一个脚本为实例演示捕获并处理 SIGWINCH 信号。我们创建名为 sigwinch_handler.sh 的脚本,其内容如下所示:
#!/bin/bash
#打印信息
echo "Adjust the size of your window now."
#捕获SIGWINCH信号
trap "echo Window size changed." SIGWINCH
#定义变量
COUNT COUNT=0
#while循环30次
while [ $C0UNT -lt 30 ]; do
#将COUNT变量的值加1
COUNT=$(($C0UNT + 1))
#休眠1秒
sleep 1
done
当上述的 Shell 脚本运行时,若改变了此脚本运行所在终端窗口的大小,脚本的进程就会收到 SIGWINCH 信号,从而调用 chwinsize 函数,以作出相应的处理。此脚本的运行结果将类似如下所示:
[c.biancheng.net]$ chmod +x sigwinch_handler.sh
[c.biancheng.net]$ ./sigwinch_handler.sh
Adjust the size of your window now.
Window size changed.
Window size changed.
我们通过上一节《十九、Linux Shell trap命令:捕获信号》的学习已经知道,在 trap 命令中可以调用函数来处理相应的信号。下面我们就以脚本 trapbg_clearup.sh 为例,来进一步学习如何使用 trap 语句调用函数来处理信号,其脚本内容如下所示:
#!/bin/bash
#捕获INT和QUIT信号,如果收到这两个信号,则执行函数 my_exit 后退出
trap 'my_exit; exit' SIGINT SIGQUIT
#捕获HUP信号
trap 'echo Going down on a SIGHUP - signal 1, no exiting...; exit' SIGHUP
#定义count变量
count=0
#创建临时文件
tmp_file=`mktemp /tmp/file.$$.XXXXXX`
#定义函数my_exit
my_exit()
{
echo "You hit Ctrl-C/CtrI-\, now exiting..."
#清除临时文件
rm -f $tmp_file >& /dev/null
}
#向临时文件写入信息
echo "Do someting..." > $tmp_file
#执行无限while循环
while :
do
#休眠1秒
sleep 1
#将count变量的值加1
count=$(expr $count + 1)
#打印count变量的值
echo $count
done
当上述脚本运行时,接收到 SIGINT 或 SIGQUIT 信号后会调用 my_exit 函数后退出(trap 命令列表中的 exit 命令),my_exit 函数会做一些清理临时文件的操作。我们运行此脚本,然后在另一个终端窗口中查看此脚本创建的临时文件:
[c.biancheng.net]$ ls -trl /tmp/ | tail -l
将会看到类似如下的文件信息:
-rw------- 1 mozhiyan mozhiyan 15 Feb 6 22:09 file.6668.RI6669
现在,在脚本运行的终端窗口,我们输入 Ctrl+C 或 Ctrl+\ 组合键来终结或退出此脚本, 将会看到类似如下的信息:
[c.biancheng.net]$ ./trapbg_clearup.sh
1
2
3
4
5
6
7
8
9
You hit Ctrl+C/Ctrl+\, now exiting...
然后我们再查看一下脚本创建的临时文件是否巳被清理:
[c.biancheng.net]$ ls -l /tmp/file.6668.RI6669
ls: /tmp/file.6668.RI6669: No such file or directory
当脚本运行在后台时,同样可以捕获信号。我们将上例中的脚本 trapbg_clearup.sh 放在后台运行:
[c.biancheng.net]$ ./trapbg_clearup.sh &
[1] 16957
[c.biancheng.net]$ 1
2
3
现在从另一个终端窗口,发送 HUP 信号来杀掉这个运行脚本的进程:
[c.biancheng.net]$ kill -l 16957
现在,在脚本运行的终端窗口,将看到类似如下的信息:
[c.biancheng.net]$ ./trapbg_clearup.sh &
[1] 16957
[c.biancheng.net]$ 1
2
3
4
5
6
7
8
9
10
Going down on a SIGHUP - signal 1, now exiting...
[1]+ Done ./trapbg_clearup.sh
LINENO 和 BASH_COMMAND 变量
Bash Shell 中有两个内部变量可以方便地在处理信号时,为我们提供更多的与脚本终结相关的信息。这两个变埴分别是 LINENO 和 BASH_COMMAND。BASH_COMMAND是 Bash 中特有的。这两个变量分别用于报告脚本当前执行的行号和脚本当前运行的命令。
下面,我们以脚本 trap_report.sh 为实例,学习如何在脚本中使用变量 LINENO 和 BASH_COMMAND 在脚本终结时为我们提供更多的错误信息,其脚本内容类似如下所示:
#!/bin/bash
#捕获SIGHUP、SIGINT和SIGQUIT信号。如果收到这些信号,将执行函数my_exit后退出
trap 'my_exit $LINENO $BASH_COMMAND; exit' SIGHUP SIGINT SIGQUIT
#函数my_exit
my_exit()
{
#打印脚本名称,及信号被捕获时所运行的命令和行号
echo "$(basename $0) caught error on line : $1 command was: $2"
#将信息记录到系统日志中
logger -p notice "script: $(basename $0) was terminated: line: $1, command was $2"
#其他一些清埋命令
}
#执行无限while循环
while :
do
#休眠1秒
sleep 1
#将变量count的值加1
count=$(expr $count + 1)
#打印count变量的值
echo $count
done
当上述脚本运行时,向脚本发送 SIGHUP、SIGINT 和 SIGQUIT 信号后,脚本将会调用 my_exit 函数,此函数将解析参数 $l(LINENO) 和 $2(BASH_COMMAND),显示信号被捕获时脚本所运行的命令及其行号,同样 logger 语句会记录信息到日志文件 /var/log/messages 中。如果需要,还可以在此函数中执行一些清理命令,然后脚本将会退出(trap 命令列表中的 exit 命令)。
此脚木的运行结果将会类似如下所示:
[c.biancheng.net]$ ./trap_report.sh
1
2
3
4
5
trap_report.sh caught error on line : 34 command was: sleep
在 /var/log/messages 文件中,将会看到一条类似如下的记录:
Feb 7 16:48:13 localhost mozhiyan: script: trap_report.sh was terminated: line: 34, command was sleep
我们在上一节《十九、Linux Shell trap命令:捕获信号》中已经学习了,使用 trap 语句可以忽略信号。你也同样可以在脚本的—部分中忽略某些信号,然后,当你希望捕获这些信号时,可以重新定义它们来采取一些行动。我们以脚本 trapoff_on.sh 为例,在此脚本中我们将忽略信号 SIGINT 和 SIGQUIT,直到 sleep 命令结束运行后为止。然后当下一个 sleep 命令开始时,如果接收到终结信号,trap 语句将采取相应的行动。
其脚木的内容如下所示:
#!/bin/bash
#忽略SIGINT和SIGQUIT信号
trap ' ' SIGINT SIGQUIT
#打印提示信息
echo "You cannot terminate using ctrl+c or ctrl+\!"
#休眠10秒
sleep 10
#重新捕获SIGINT和SIGQUIT信号。如果捕获到这两个信号,则打印信息后退出
#现在可以中断脚本了
trap 'echo Terminated!; exit' SIGINT SIGQUIT
#打印提示信息
echo "OK! You can now terminate me using those keystrokes"
#休眠10秒
sleep 10
此脚本的运行结果将类似如下所示:
[c.biancheng.net]$ chmod +x trapoff_on.sh
[c.biancheng.net]$ ./trapoff_on.sh
You cannot terminate using ctrl+c or ctrl+\!
OK! You can now terminate me using those keystrokes.
Terminated!
二十一、Linux Shell移除(重置)信号捕获
如果我们在脚本中应用了捕获,我们通常会在脚本的结尾处,将接收到信号时的行为处理重置为默认模式。重置(移除)捕获的语法如下所示:
$ trap - signal [ signal ... ]
从上述语法中可以看出,使用破折号作为 trap 语句的命令参数,就可以移除信号的捕获。
下面,我们以脚本 trap_reset.sh为例,来学习如何在脚本中移除先前定义的捕获。其脚本的内容类似如下所示:
#!/bin/bash
#定义函数cleanup
function cleanup {
#如果变量 msgfile 所指定的文件存在
if [[ -e $msgfile ]]; then
#将文件重命名(或移除)
mv $msgfile $msgfile.dead
fi
exit
}
#捕获INT和TERM信号
trap cleanup INT TERM
#创建一个临时文件
msgfile=`mktemp /tmp/testtrap.$$.XXXXXX`
#通过命令行向此临时文件中写入内容
cat > $msgfile
#接下来,发送临时文件的内容到指定的邮件地址,你自己完善此部分代码
#send the contents of $msgfile to the specified mail address...
#删除临时文件
rm $msgfile
#移除信号INT和TERM的捕获
trap - INT TERM
上述脚本中,在用户已经完成了发送邮件的操作之后,临时文件会被删除。这时,因为已经不再需要清理操作,我们可以重置信号的捕获到默认状态,所以我们在脚本的最后一行重置了 INT 和 TERM 信号的捕获。
二十二、关于Linux Shell中进程、信号和捕获的总结
下面我们总结一下前面几节学到的关于进程、信号和捕获的主要知识。
在 Linux 系统和其他类 Unix 或 Unix 操作系统中,信号被用于进程间的通信。
信号是一个发送到某个进程或同一进程中的特定线程的异步通知,用于通知发生的一个事件。
在 Linux 中,信号在处理异常和中断方面,扮演了极其重要的角色。
当一个事件发生时,会产生一个信号,然后内核会将事件传递到接收的进程。
运行在用户模式下的进程会接收信号。如果接收的进程正运行在内核模式,那么信号的执行只有在该进程返回到用户模式时才会开始。
当进程收到一个信号时,可能会发生以下3种情况:
- 进程可能会忽略此信号。有些信号不能被忽略,而有些没有默认行为的信号,默认会被忽略。
- 进程可能会捕获此信号,并执行一个被称为信号处理器的特殊函数。
- 进程可能会执行信号的默认行为。例如,信号 15(SIGTERM) 的默认行为是结束进程。
在Shell命令行提示符下,输入“kill -l”命令,可以显示所有信号的信号值和相应的信号名。
由 Bash Shell 运行的非内部命令会使用 Shell 从其父进程继承的信号处理程序。
默认情况下,Shell 接收到 SIGHUP 信号后会退出。在退出之前,一个交瓦式的 Shell 会向所有的作业,不管是正在运行的还是已停止的,重新发送 SIGHUP 信号。
若要阻止 Shell 向某个特定的作业发送 SIGHUP 信号,可以使用内部命令 disown 将它从作业表中移除,或是用“disown -h”命令阻止 Shell 向特定的作业发送 SIGHUP 信号,但并不会将特定的作业从作业表中移除。
进程是运行在 Linux 中的程序的一个实例。
每当你在 Linux 中执行一个命令,它都会创建或启动一个新的进程。
有两种运行方式的进程:前台进程和后台进程。
进程可以有5种状态:不可中断休眠状态(D)、运行状态(R)、休眠状态(S)、 停止状态(T)和僵死状态(Z)。
使用 ps 命令,可以查看当前的进程;使用 pstree 命令,可以显示进程树的信息;使用 pgrep 命令,可以基于名称或其他属性查找进程。
当准备杀掉一个进程或一连串的进程时,我们的常识是从尝试发送最安全的信号开始,即 SIGTERM 信号。
如果发送一个 SIGKILL 信号到进程,将消除进程先清理而后关闭的机会,这可能导致不幸的结果。但如果一个有序地终结不管用,那么发送 SIGINT 或 SIGKILL 信号就可能是唯一的方法了。
killall 命令会发送信号到运行任何指定命令的所有进程。
使用 pkill 命令,可以通过指定进程名、用户名、组名、终端、UID、EUID 和 GID 等属性来杀掉相应的进程。pkill 命令默认也是发送 SIGTERM 信号到进程。
Bash 的内部命令 trap,让我们可以在 Shell 脚本内捕获特定的信号并对它们进行处理。
使用空字符串""或''作为 trap 的命令参数,可以让 Shell 忽略指定的信号。
除 SIGKILL 信号以外,其他任何信号都可以被捕获并通过调用C语言函数 signal 处理。
Bash中有两个内部变量 LINENO 和 BASH_COMMAND 可以方便地在处理信号时,分别用于报告脚本当前执行的行号和脚本当前运行的命令。
使用破折号作为 trap 语句的命令参数,就可以移除指定信号的捕获。
二十三、Shell模块化(把代码分散到多个脚本文件中)
所谓模块化,就是把代码分散到多个文件或者文件夹。对于大中型项目,模块化是必须的,否则会在一个文件中堆积成千上万行代码,这简直是一种灾难。
基本上所有的编程语言都支持模块化,以达到代码复用的效果,比如,Java 和 Python 中有 import,C/C++ 中有 #include。在 Shell 中,我们可以使用 source 命令来实现类似的效果。
在《Shell基础 十一:执行Shell脚本》一节中我们已经提到了 source 命令,这里我们再来讲解一下。
source 命令的用法为:
source filename
也可以简写为:
. filename
两种写法的效果相同。对于第二种写法,注意点号.和文件名中间有一个空格。
source 是Shell内置命令的一种,它会读取 filename 文件中的代码,并依次执行所有语句。你也可以理解为,source 命令会强制执行脚本文件中的全部命令,而忽略脚本文件的权限。
1、实例
创建两个脚本文件 func.sh 和 main.sh:func.sh 中包含了若干函数,main.sh 是主文件,main.sh 中会包含 func.sh。
func.sh 文件内容:
#计算所有参数的和
function sum(){
local total=0
for n in $@
do
((total+=n))
done
echo $total
return 0
}
main.sh 文件内容:
#!/bin/bash
source func.sh
echo $(sum 10 20 55 15)
运行 main.sh,输出结果为:
100
source 后边可以使用相对路径,也可以使用绝对路径,这里我们使用的是相对路径。
2、避免重复引入
熟悉 C/C++ 的读者都知道,C/C++ 中的头文件可以避免被重复引入;换句话说,即使被多次引入,效果也相当于一次引入。这并不是 #include 的功劳,而是我们在头文件中进行了特殊处理。
Shell source 命令和 C/C++ 中的 #include 类似,都没有避免重复引入的功能,只要你使用一次 source,它就引入一次脚本文件中的代码。
那么,在 Shell 中究竟该如何避免重复引入呢?
我们可以在模块中额外设置一个变量,使用 if 语句来检测这个变量是否存在,如果发现这个变量存在,就 return 出去。
这里需要强调一下 return 关键字。return 在 C++、C#、Java 等大部分编程语言中只能退出函数,除此以外再无他用;但是在 Shell 中,return 除了可以退出函数,还能退出由 source 命令引入的脚本文件。
所谓退出脚本文件,就是在被 source 引入的脚本文件(子文件)中,一旦遇到 return 关键字,后面的代码都不会再执行了,而是回到父脚本文件中继续执行 source 命令后面的代码。
return 只能退出由 source 命令引入的脚本文件,对其它引入脚本的方式无效。
下面我们通过一个实例来演示如何避免脚本文件被重复引入。本例会涉及到两个脚本文件,分别是主文件 main.sh 和 模块文件 module.sh。
模块文件 module.sh:
if [ -n "$__MODULE_SH__" ]; then
return
fi
__MODULE_SH__='module.sh'
echo "http://c.biancheng.net/shell/"
注意第一行代码,一定要是使用双引号把$__MODULE_SH__包围起来,具体原因已经在《Shell编程 三十一:Shell test命令(Shell [])详解,附带所有选项及说明》一节中讲到。
主文件 main.sh:
#!/bin/bash
source module.sh
source module.sh
echo "here executed"
./表示当前文件,你也可以直接写作source module.sh。
运行 main.sh,输出结果为:
http://c.biancheng.net/shell/
here executed
我们在 main.sh 中两次引入 module.sh,但是只执行了一次,说明第二次引入是无效的。
main.sh 中的最后一条 echo 语句产生了输出结果,说明 return 只是退出了子文件,对父文件没有影响。
十二月5日上午发
相关文章:
Shell脚本:Linux Shell脚本学习指南(第三部分Shell高级)四
十九、Linux Shell trap命令:捕获信号 到目前为止,我们在本教程所见的脚本中还没有需要信号处理功能的,因为它们的内容相对比较简单,执行时间很短,而且不会创建临时文件。而对于较大的或者更复杂的脚本来说࿰…...
牛气霸屏-快抖云推独立版V1.6.7
介绍 快抖云推全插件独立版是最近很火的牛气霸屏系统独立版,牛气霸屏系统就是商家通过系统在线创建抖音或快手霸屏活动,并生成该活动的爆客二维码,用户通过扫二维码即可参加活动(活动可以是领取卡劵,抽奖等࿰…...
ffmpeg下载与配置环境变量
FFmpeg 是一个强大的多媒体框架,可以让用户处理和操纵音频和视频文件。具有易于使用的界面,用户可以在 Windows、Mac 或 Linux Ubuntu 系统上下载 FFmpeg 并将其提取到文件夹中。然后,该软件可以加入 PATH 环境变量中就可以快捷的使用软件了.…...
那些年,关于CKACKS认证的那些事儿?
前言 遥想2020年的年初,疫情封城封村之际,工作之余在B站将尚硅谷的linux中的k8s视频完整系统的学习了一遍,自此像是打通了任督二脉一般,开启了对k8s的探索之旅,一路也是磕磕绊绊的在工作中使用k8s。 终于在23年的6月仲…...
chromium通信系统-mojo系统(一)-ipcz系统代码实现-同Node通信
在chromium通信系统-mojo系统(一)-ipcz系统基本概念一文中我们介绍了ipcz的基本概念。 本章我们来通过代码分析它的实现。 handle系统 为了不对上层api暴露太多细节,实现解耦,也方便于传输,ipcz系统使用handle表示一个对象,hand…...
电路 buck-boost相关知识
BUCK-BOOST 文章目录 BUCK-BOOST前言一、DC-DC工作模式电容电感特性伏秒积平衡原理 二、BUCK电路三、BOOST电路四、BUCK-BOOST电路总结 前言 最近需要用到buck-boost相关的电路知识,于是便写下这篇文章复习一下。 一、DC-DC 在学习buck-boost电路之前我们先来看一…...
音频——S/PDIF
文章目录 BMC 编码字帧(sub-frame)格式帧(frame)格式参考S/PDIF 是 SONY 和 Philips 公司共同规定的数字信号传输规范,其实就是在 AES/EBU 上进行改动的家用版本。IEC60958 的标准规范囊括了以上两个规范。spdif 采用了双相符号编码(BMC),是将时钟信号和数据信号混合在一起…...
100篇带你入门——嵌入式系统中的程序调试方法
好久不见,最近小猿有点忙,才有时间给大家写文章。今天给大家讲一下在我们单片机开发都用哪些调试工具和调试方法,内容不完善的话,欢迎大家一起交流。 当涉及到嵌入式系统的程序调试时,选择正确的工具和方法是确保系统功…...
【Spring】Spring事务失效问题
📫作者简介:小明java问道之路,2022年度博客之星全国TOP3,专注于后端、中间件、计算机底层、架构设计演进与稳定性建设优化,文章内容兼具广度、深度、大厂技术方案,对待技术喜欢推理加验证,就职于…...
WiFi 发射链路 MCS 自适应机制介绍
链路适配是指发射机选择最优的MCS向特定的接收机发送数据的过程。链路自适应算法的实现有其特殊性,但通常基于测量的数据包错误率(PER)。大多数算法监视PER并调整MCS以跟踪一个最佳的长期平均值,以平衡由于使用更高MCS发送更短数据包而减少的开销和由于更…...
【Linux常用命令】-文件写入相关
一、rm命令,文件删除 1.相关参数 -f(–force):强制删除文件或目录,无需确认。 -r(–recursive):递归地删除目录及其内容。 -i(–interactive):交…...
枚举的第一行
2023年11月26日 问题: 好奇enum的所声明的枚举类的第一行是什么 从java技术卷1中第五章5.6中,了解是枚举类的实例 验证 错误信息: 解释: 此时只有有参构造 在这个枚举类里不能使用空,大概意思是说不能使用空参创建实例 校验 在原有的基础上创建一个无参构造 结果:不再报错,第…...
LeetCode.707设计链表(链表相关操作一篇就够了)
LeetCode.707设计链表 1.问题描述2.解题思路3.代码 1.问题描述 你可以选择使用单链表或者双链表,设计并实现自己的链表。 单链表中的节点应该具备两个属性:val 和 next 。val 是当前节点的值,next 是指向下一个节点的指针/引用。 如果是双…...
图论——二部图及其算法
什么是二部图 二部图的判定 例子1 任选一个节点染成红色 红色的邻居染成蓝色 蓝色邻居染成红色 例子2 这个不是二部图 无权二部图的最大匹配...
实现简单的操作服务器和客户端(下)
一、说明 描述:本教程介绍如何使用 simple_action_client 库创建斐波那契操作客户端。此示例程序创建一个操作客户端并将目标发送到操作服务器。 内容 代码代码解释编译运行操作客户端连接服务器和客户端...
第二十章 解读PASCAL VOC2012与MS COCO数据集(工具)
PASCAL VOC2012数据集 Pascal VOC2012官网地址:http://host.robots.ox.ac.uk/pascal/VOC/voc2012/ 官方发表关于介绍数据集的文章 《The PASCALVisual Object Classes Challenge: A Retrospective》:http://host.robots.ox.ac.uk/pascal/VOC/pubs/everi…...
FreeRTOS列表和列表项
目录 列表和列表项 关于列表的一些操作 初始化列表 初始化列表项 列表插入列表项 列表项末尾插入 重点 pxIndex指向的是什么 xItemValue存的是什么 vListInsertEnd()的插入位置 List的头尾在哪里? 通用链表的三种实现方式 方法一 方法二 方法三 总结 Fre…...
【go语言实现一个webSocket的一个demo】
go语言实现一个webSocket的一个demo 前端代码 <html lang"zh-CN"><head></head><body> <script type"text/javascript">// header(Access-Control-Allow-Origin:*);var sock null;var wsuri "ws://127.0.0.1:9999&…...
es6字符串模板之标签化模板
es6字符串模板 我们经常搞前端开发工作的都会用到。它可以保留字符串换行格式,还能接受变量。这个给前端的字符串拼接带来了非常大的方便。但是还有一种用法可能是我们平时还是没有怎么用到的。 styled-components 在项目中熟悉使用react的童鞋可能会用过styled-…...
opencv入门1.1:从视频或摄像头读取图像
cv::VideoCapture是 OpenCV 中用于从视频文件或摄像头捕获图像帧的类。它提供了各种方法和函数,用于读取和处理视频数据。 以下是对 cv::VideoCapture类的详细解释和说明: 1. 打开视频源 为了使用 cv::VideoCapture,我们首先需要打开一个视…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...
多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验
一、多模态商品数据接口的技术架构 (一)多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...
华为OD机试-食堂供餐-二分法
import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...
如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...
排序算法总结(C++)
目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指:同样大小的样本 **(同样大小的数据)**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...
深度学习水论文:mamba+图像增强
🧀当前视觉领域对高效长序列建模需求激增,对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模,以及动态计算优势,在图像质量提升和细节恢复方面有难以替代的作用。 🧀因此短时间内,就有不…...
【JavaSE】多线程基础学习笔记
多线程基础 -线程相关概念 程序(Program) 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存…...
FFmpeg:Windows系统小白安装及其使用
一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】,注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录(即exe所在文件夹)加入系统变量…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
基于Uniapp的HarmonyOS 5.0体育应用开发攻略
一、技术架构设计 1.混合开发框架选型 (1)使用Uniapp 3.8版本支持ArkTS编译 (2)通过uni-harmony插件调用原生能力 (3)分层架构设计: graph TDA[UI层] -->|Vue语法| B(Uniapp框架)B --&g…...
