翻译:-How-to-modify-scripts-behavior-on-signals-using-bash-traps

#

/Users/sqsgalaxys/Downloads/sqsgalaxys.github.io/source/_posts/How-to-modify-scripts-behavior-on-signals-using-bash-traps.md
原文:
How to modify scripts behavior on signals using bash traps - LinuxConfig.org

目的

这篇教程在于描述如何使用bash shell 内建的 trap命令来使我们的脚本在它接收到一个信号或在其他特定的情形时有特定的操作

要求

无特殊要求

难度

容易

约定

- 代表给出的命令应该以 root 权限执行(直接以 root 用户来执行或使用 sudo 命令执行)

$ - 代表给出的命令应该以普通权限的用户执行

介绍

当我们写一个重要的脚本,通过使它们可以响应系统的某些信号执行特定的操作,提高它们的鲁棒性是非常重要的.
我们可以通过 bash shell 内建的 trap 达到这一目的.

什么是 traps?

trap 是一个 bash 机制 它可以自定义脚本的接收到信号时的操作. 这在保证系统在执行脚本出错后恢复系统是非常重要的. 比如写一个脚本,它会在运行时创建一些目录,当它在运行时接收到了 SIGINT 信号,这个脚本会被中断,它创建的目录会被留下来, 我没可以使用traps命令来做一些清除目录的操作.

Trap 语法

Trap 语法非常简单和易懂:
调用内建的 trap 命令 紧接着在接受到特定信号时需要被执行的命令并指定我们要处理的信号
trap [-lp] [[arg] sigspec]
让我们看看 trap 选项的作用
当使用 -l 的选项,trap 命令仅仅显示信号及其对应的数字, 同样的输出你可以通过运行 kill -l 命令来获取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ trap -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX

非常重要的是 trap 命令只能重新定义可以被脚本响应的信号,像 SIGKILL 和 SIGSTOP 信号不能被捕获,屏蔽或忽略.

除了信号,traps 也可以重新定义一些 伪信号,比如 EXIT, ERR(错误) or DEBUG,在以后后面会深入这些细节
现在我们只要记住,信号可以通过它的名字或它他的数字 甚至可以没有 SIG 前缀,来指定

trap 的 -p 选项,-p 选项的前面不能有命令,否则会报错,
-p 选项会列出已经设置 trap 的信号和对应的列表.
如果指定信号的名字或数字被指定这会列出对应信号对应被设置的 trap 规则,不指定信号的名称或数字的则会显示所有被设置 trap 的信号

$ trap 'echo "SIGINT caught!"' SIGINT

我们设置了一个 trap 来捕获 SIGINT 信号,它仅仅是展示 “SIGINT caught” 信息在屏幕上当指定的信号被 shell 接收到
如果我们使用trap 的 -p 选项,这会展示我们刚刚定义的 trap

1
2
$ trap -p
trap -- 'echo "SIGINT caught!"' SIGINT

顺便说一句,这个 trap 现在是 激活的,所以如果我们发送一个 SIGINT 信号,或者使用 kill 命令,或者使用 CTRL-c 快捷键,trap 中绑定的命令将会被执行
(只是打印出 ^C 是因为快捷键绑定(combination)

1
2
^C
SIGINT caught!

Trap 实战

我们现在来写一个简单的脚本,下面就是

1
2
3
4
5
6
7
8
9
10
11
12
#!/usr/bin/env bash
#
# A simple script to demonstrate how trap works
#
set -e
set -u
set -o pipefail

trap 'echo "signal caught, cleaning..."; rm -i linux_tarball.tar.xz' SIGINT SIGTERM

echo "Downloading tarball..."
wget -O linux_tarball.tar.xz https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.13.5.tar.xz &> /dev/null

上面的脚本只是试图下载最新的 linux kernel tarball 到启动 wget 的目录 在执行这任务时如果接收到了 SIGINT 或 SIGTERM 信号 (注意你如何在一行中指定不止一个信号) 下载的部分文件会被删除

In this case the command are actually two: the first is the echo which prints the message onscreen, and the second is the actual rm command (we provided the -i option to it, so it will ask user confirmation before removing), and they are separated by a semicolon. Instead of specifying commands this way, you can also call functions: this would give you more re-usability. Notice that if you don’t provide any command the signal(s) will just be ignored!
在这个例子中,命令实际是两个,第一个是 echo 第二个是实际执行 rm 命令,我们提供 -i 选项给他, 所以它会在删除前要求用户确认 而且他们以逗号分割,除了这样指定命令以外,你也可以调用函数,这样可以给你高可用性 注意,如果你不提供任何命令,信号会被忽略

这是在接收到 SIGINT 信号时,脚本的输出:

1
2
3
4
$ ./fetchlinux.sh
Downloading tarball...
^Csignal caught, cleaning...
rm: remove regular file 'linux_tarball.tar.xz'?

记住一个非常重要的点: 像上面这样当一个脚本通过信号终止, 他的退出码将是 128 与信号数字的和, 你可以看到,

1
2
$ echo $?
130

最后,你可以停用 trap:调用 trap 紧跟着 sign 跟着 信号的名字或者数字

trap - SIGINT SIGTERM
这个信号将会恢复原来的作用

伪信号

就像上面提到的 trap 不仅可以被用来让脚本响应信号,也可以响应被称作假冒信号的信号 它们不是典型的信号,但是一致的确定的情形也可以被指定 trap

EXIT

当 EXIT 被指定在 trap 中,被 trap 命令参数将会在退出 shell 时执行

ERR (错误)

当一个命令返回一个非零的退出值, 附带一些异常时 trap 的参数被执行.它和 shell errexit 选项类似 这个命令必须不是一个 while 或 until 循环的一部分, 它必须不是 if 条件的一部分,也不能是 && 或 || 条件的一部分 并且它的值不能通过 ! 反转

DEBUG

This will cause the argument of the trap to be executed before every simple command, for, case or select commands, and before the first command in shell functions
trap 的命令参数将会在一些非常简单的命令 for case 或者 select 命令后,并且在 shell 函数的第一个命令之前执行

RETURN
返回
The argument of the trap is executed after a function or a script sourced by using source or the . command.
trap 的命令参数将会在以下情形执行:

  • 执行完一个函数
  • 一个脚本被 source命令加载
  • . 命令
分享到 评论

Reload-Spring-Boot-ProperTies

动态改变Spring Boot 的属性需要依赖Spring Cloud 的一些东西
spring-cloud-config-server spring-cloud-config-client
个人认为

分享到 评论

IDEA自定义Javadoc_tag的保存位置


参考:
How to remove an custom javadoc tag from Intellij-IDEA - Stack Overflow

ps:水了一篇.

分享到 评论

最近接触的字符编码相关总结

\u00a0

从网页上复制代码粘贴到 IDEA 中,IDEA 报错:
Error:(18, 1) java: illegal character: '\u00a0'
这个'\u00a0'是什么?
是从哪来的呢?

\u00A0 其实就是   代表 non-breaking space(不间断空白)
关于  , 严格语义上来说,使用场景是不希望自动换行时使用。但现实中,绝大部分情况下,  就用来表示纯粹的空格。因为多个字符空格在 html 中会被当成一个空格,为了连续输出多个空格,只好用   (毕竟用 css 控制太麻烦)。按理说用多个 输出多个空格是最好的选择,但强大的 html 引擎依旧会把多个 转换成一个。
jQuery 的 trim 方法加入 \u00A0, 是种无奈,但也是一种对现实标准的认可。
一切皆权衡。

参考:

如何打出复制 \u00a0

Chrome 使用开发者工具选择带有&nbsp空格的元素,然后在 Console 输入:copy($0.innerText)即可把带有&nbsp空格的文本复制到粘贴板中.
其他方法:
什么是 不换行空格 意思详解 - 淘大白

Java 与 Unicode

Versions of the Java programming language prior to JDK 1.1 used Unicode 1.1.5.
Upgrades to newer versions of the Unicode Standard occurred in JDK 1.1 (to Unicode 2.0),
JDK 1.1.7 (to Unicode 2.1),
Java SE 1.4 (to Unicode 3.0),
Java SE 5.0 (to Unicode 4.0),
Java SE 7 (to Unicode 6.0),
and Java SE 8 (to Unicode 6.2).

参考:
The Java ® Language Specification Java SE 8 Edition 3.1 Unicode

其他:

的码点:U+355C

分享到 评论

记录 Linux 磁盘空间被占满的解决过程

记录 Linux 磁盘空间被占满的解决过程

查看磁盘占用情况

1
2
3
4
5
6
7
8
-----------» df -lh
Filesystem Size Used Avail Use% Mounted on
/dev/vda1 30G 30G 20K 100% /
devtmpfs 911M 0 911M 0% /dev
tmpfs 920M 16K 920M 1% /dev/shm
tmpfs 920M 89M 831M 10% /run
tmpfs 920M 0 920M 0% /sys/fs/cgroup
tmpfs 184M 0 184M 0% /run/user/0

不断查看 / 下面目录文件(夹)大小找到大文件(夹)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
-----------» cd / && du -sh *
0 bin
148M boot
16K dev
178M etc
1.3G home
0 lib
0 lib64
0 media
4.0K meta.js
0 mnt
3.9G opt
du: cannot access ‘proc/5030/task/5030/fd/4’: No such file or directory
du: cannot access ‘proc/5030/task/5030/fdinfo/4’: No such file or directory
du: cannot access ‘proc/5030/fd/4’: No such file or directory
du: cannot access ‘proc/5030/fdinfo/4’: No such file or directory
0 proc
1.6G root
89M run
0 sbin
0 srv
0 sys
12K tmp
68K Users
3.7G usr
20G var
-----------» cd /var && !!
-----------» cd /var && du -sh *
0 adm
107M cache
0 crash
220K db
0 empty
0 games
0 gopher
0 kerberos
2.2G lib
0 local
0 lock
17G log
0 mail
0 nis
16K opengrok
0 opt
0 preserve
0 run
132K spool
4.0K tmp
....

可以看到 log 文件夹有 17 GB 大小,进入log目录查看目录下文件大小:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
-----------» ^var^var/log
-----------» cd /var/log && du -sh *
0 agent_debug_info_msgs.log
1.8M AgentMonitor.log
11M AgentMonitor.log.1
11M AgentMonitor.log.2
11M AgentMonitor.log.3
11M AgentMonitor.log.4
11M AgentMonitor.log.5
3.6M ambari-server
1.2M anaconda
34M audit
0 auth.log
0 boot.log
0 boot.log-20180111
12K boot.log-20180112
0 boot.log-20180115
0 boot.log-20180116
0 boot.log-20180117
0 boot.log-20180119
0 boot.log-20180120
4.8M btmp
10M btmp-20180101
5.9M CloudAgent.log
11M CloudAgent.log.1
11M CloudAgent.log.10
11M CloudAgent.log.2
11M CloudAgent.log.3
11M CloudAgent.log.4
11M CloudAgent.log.5
11M CloudAgent.log.6
11M CloudAgent.log.7
11M CloudAgent.log.8
11M CloudAgent.log.9
0 CloudUpdate_debug_info_msgs.log
1.4M CloudUpdate.log
24K cron
44K cron-20171224
52K cron-20171231
52K cron-20180107
40K cron-20180115
1.7M denyhosts
32K dmesg
0 dmesg.0
32K dmesg.old
0 dpkg.log
4.0K grubby
4.0K grubby_prune_debug
488K httpd




17G jenkins




24K lastlog
0 maillog
0 maillog-20171224
0 maillog-20171231
0 maillog-20180107
0 maillog-20180115
1.1M messages
27M messages-20171224
31M messages-20171231
28M messages-20180107
18M messages-20180115
184K mongodb
92K mysqld.log
84K nginx
0 ntp
24K ntp.log
0 ntpstats
0 ppp
4.0K privoxy
0 qemu-ga
544K secure
860K secure-20171224
36K secure-20171231
820K secure-20180107
564K secure-20180115
880K secure.bak
2.1M shadowsocksr.log
0 spooler
0 spooler-20171224
0 spooler-20171231
0 spooler-20180107
0 spooler-20180115
0 tallylog
48K tuned
4.0K udinstall.log
0 wpa_supplicant.log
308K wtmp
4.0K yum.log
36K yum.log-20180101

删除大文件(夹)

jenkins 的日志有 17GB,赶紧停止 jenkins:

1
2
3
-----------» service jenkins stop   
Stopping jenkins (via systemctl): [ OK ]
-----------»

删除 jenkins 日志:

1
rm -rf /var/log/jenkins

命令总结:

1
2
3
4
# 查看磁盘使用情况
df -lh
# 查看当前文件夹下面文件(夹)的大小
du -sh *

学习到的经验:

在装完一个应用后需要观察应用一段时间,看看系统的运行是否正常.

分享到 评论

Python 爬虫爬取 chrome webstore

Python 爬虫爬取 chrome webstore

插件本地存放目录:
~/Library/Application Support/Google/Chrome/Default/Extensions

插件地址 = 'https://chrome.google.com/webstore/detail/' + 插件存放目录里的文件夹名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# -*- coding: utf-8 -*-
import socket
import socks
import requests
from bs4 import BeautifulSoup
import time

SOCKS5_PROXY_HOST = '127.0.0.1'
SOCKS5_PROXY_PORT = 1086 # socks 代理本地端口
default_socket = socket.socket
socks.set_default_proxy(socks.SOCKS5, SOCKS5_PROXY_HOST, SOCKS5_PROXY_PORT)
socket.socket = socks.socksocket

# url = 'https://chrome.google.com/webstore/detail/infolite/ipjbadabbpedegielkhgpiekdlmfpgal'
baseUrl = 'https://chrome.google.com/webstore/detail/'

extensions = [
'aabcgdmkeabbnleenpncegpcngjpnjkc',
'aajodjghehmlpahhboidcpfjcncmcklf',
'aalnjolghjkkogicompabhhbbkljnlka'
]

for extension in extensions:
url = baseUrl + extension
html_source = requests.get(url, headers={
"User-Agent": "Mozilla/5.001 (windows; U; NT4.0; en-US; rv:1.0) Gecko/25250101"}).text
if html_source:
try:
soup = BeautifulSoup(html_source, 'html.parser')
# <h1 class="e-f-w">OneTab</h1>
# 插件的标题
# print("标题: " + soup.html.find_all("title")[0].text)
# 合成 markdown 链接
title = soup.html.find_all("title")[0].text
print('### [' + title + ']' + '(' + url + " '0.0'" + ')')
# <pre class="C-b-p-j-Oa">
# 插件的自我介绍
print(soup.find_all("pre", class_="C-b-p-j-Oa")[0].text)
except:
# 发生异常,执行这块代码
print('fail for: ' + '[' + url + ']')
else:
print('ok')
# 如果没有异常执行这块代码
else:
print('fail for: ' + '[' + url + ']')
# Wait for 5 seconds
time.sleep(4)

参考:

分享到 评论

ideavim 设置面板的简单分析

The cause of this

本来想写一篇 ideavim 设置中 vim 的快捷键与 idea 本身快捷键的对比,但是经过搜索发现已经有一片类似的博客了:
JetBrains IDE Vim 模式的方案 | I sudo X(这篇博客貌似有个彩蛋:点击页脚眼睛标志旁边的数字)
注意到设置面板中的 “Shortcut Conflicts for Active Keymap”,(活动的Keymap的快捷冲突)
而且这篇博客中对比的快捷键和我 IntelliJ IDEA 中的 Vim Emulation 设置不太一样
我的 ideavim 设置面板
所以猜想是不是这个 列表是不是根据快捷键的冲突动态生成的

查看更多

分享到 评论

无意

无意

我无意中发现他无意中发现了这个 Chinese Text Project 网站.

参考:

无意之中发现一个不错的网站 | | rix的笔记

分享到 评论