本文会不定期更新 :)
set#
可以使用set命令改变shell脚本默认的执行流程。
比如 set -e
可以使得shell脚本遇到某一条命令出错( echo $?
不为0)时立即退出执行。
1
2
3
4
| #/bin/bash
set -e
false
echo you cannot see me, unless you comment out the 'set -e' flag, haha
|
set详细文档
1
2
| ❯ du -sh Downloads
4.1G Downloads
|
wiki
1
| rm $0 # 删除当前文件 for cleanup
|
job#
nohup#
在后台执行当前命令:
1
| nohup /usr/sbin/script.sh &
|
默认情况下,进程是前台进程,这时就把Shell给占据了,我们无法进行其他操作,对于那些没有交互的进程,
我们希望将其在后台启动,可以在启动参数的时候加一个’&‘实现这个目的。
1
2
3
4
5
| ❯ sleep 5 &
[1] 34769
✦ ❯
[1] + 34769 done sleep 5
✦ ❯
|
进程切换到后台的时候,我们把它称为job。切换到后台时会输出相关job信息,上面&的输出 [1] 34769 :
[1]表示job ID 是1,11319表示进程ID是34769。切换到后台的进程,仍然可以用ps命令查看。
fg/bg suspended#
可以通过bg (background)和fg(foreground)命令将其在前后台间状态切换。
可以使用+z 组合键把当前fg的进程挂起:
1
2
3
4
| Source changed "/Users/r/datewu.github.io/content/posts/bash-command/index.md": WRITE
Total in 15 ms
^Z
[1] + 3595 suspended hugo server
|
注意,挂起的进程会暂停运行。需要再执行bg/fg命令才能继续运行:
1
2
3
| datewu.github.io on main [!?] took 7m41s
✦ ❯ bg
[1] + 3595 continued hugo server
|
同样的,bg之后执行fg命令就可以把job重新分配到当前的shell了。
1
2
3
4
5
6
| datewu.github.io on main [!?]
✦ ❯ ls
Makefile Readme.md archetypes config.yaml content data layouts resources static themes
datewu.github.io on main [!?]
✦ ❯ fg
[1] + 3595 running hugo server
|
守护进程#
如果一个进程永远都是以后台方式启动,并且不能受到Shell退出影响而退出,一个正统的做法是将其创建为守护进程。
守护进程值得是系统长期运行的后台进程,类似Windows服务。守护进程信息通过ps –a无法查看到,需要用到–x参数。
当查看守护进程时,往往还附上-j参数以查看作业控制信息,其中TPGID一栏为-1就是守护进程。
1
2
3
4
5
| root ~ ps xj
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
953 1190 1190 1190 ? -1 Ss 1000 0:00 /bin/sh /usr/bin/startkde
1 1490 1482 1482 ? -1 Sl 1000 0:00 /usr/bin/VBoxClient –seamless
1 1491 1477 1477 ? -1 Sl 1000 0:00 /usr/bin/VBoxClient –display
|
创建守护进程最关键的一步是调用setsid函数创建一个新的Session,并成为Session Leader。
成功创建守护进程的流程为:
- 创建一个新的Session,当前进程成为Seesion Leader, 当前进程的id就是Session id;
- 创建一个新的进程组,当前进程成为进程组的Leader, 当前进程的id就是进程组的id;
- 如果当前进程原本有一个控制终端,则它会失去这个shell,成为一个没有shell的进程(即守护进程)。
可以使用的命令有 disown setsid nohup
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
| ❯ tldr disown
Command disown does not exist for the host platform. Displaying the page from linux platform
disown
Allow sub-processes to live beyond the shell that they are attached to.
See also the jobs command.
More information: https://www.gnu.org/software/bash/manual/bash.html#index-disown.
- Disown the current job:
disown
- Disown a specific job:
disown %job_number
- Disown all jobs:
disown -a
- Keep job (do not disown it), but mark it so that no future SIGHUP is received on shell exit:
disown -h %job_number
See also: jobs
~
❯ man setsid | head
SETSID(2) System Calls Manual SETSID(2)
NAME
setsid – create session and set process group ID
SYNOPSIS
#include <unistd.h>
pid_t
setsid(void);
|
exit#
1
2
3
| #/bin/bash
exit(0) #脚本/命令正常退出
exit(1) # 脚本/命令异常退出
|
$? && ||#
shell 在执行某个命令的时候,会返回一个返回值,该返回值保存在 shell 变量 $? 中。
当 $? == 0 时,表示执行成功;当 $? == 1 时(非0返回值,一般在0-255间),表示执行失败。
shell 提供了 && 和 || 来实现命令执行flow控制的功能,shell 将根据 && 或 || 前面命令的返回值来选择执行后续命令。
1
| command1 && command2 [&& command3 ...]
|
- 命令之间使用
&&
连接,实现逻辑与的功能; - 只有在
&&
左边的命令返回真(命令返回值 $? == 0
),&& 右边的命令才会被执行; - 只要有一个命令返回假(命令返回值
$? == 1
),后面的命令就不会被执行。 即是短路的功能。
1
| command1 || command2 [|| command3 ...]
|
- 命令之间使用
||
连接,实现 逻辑或的功能; - 只有在
||
左边的命令返回假(命令返回值 $? == 1
),||
右边的命令才会被执行。这和 c 语言中的逻辑或语法功能相同,即实现defult赋值操作; - 只要有一个命令返回真(命令返回值
$? == 0
),后面的命令就不会被执行。
shell语句变量无需声明,需要引用变量指时, 在变量名前添加$符号即可(有时需要配合括号消除歧义):
1
2
3
4
5
6
| var=hellhttp://sdf.com?uid=233&pwd=ls
echo var # var
echo $var # hellhttp://sdf.com?uid=233&pwd=ls
va=he
echo $valloworld # 无输出,因为没有valloworld变量
echo ${va}lloworld # hellworld
|
$()#
先执行括号里面的shell命令,然后把括号里面shell命令的输出做为新的命令去执行。
也可以使用泛引号``。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| ❯ echo ls > abc
~/codebase
❯ $(less abc) # same as `less abc`
abc gobookIread jsbook lol playaround
~/codebase
❯ $(cat abc)
abc gobookIread jsbook lol playaround
~/codebase
❯ $(ls) # same as `ls`
zsh: command not found: abc
❯ echo `date`
2021年11月17日 星期三 11时58分02秒 CST
~
❯ echo $(date)
2021年11月17日 星期三 11时58分10秒 CST
|
wget#
http basic auth
1
| wget --no-check-certificate --user user --password pass https://server_address/
|
curl#
1
2
3
4
5
| curl -I google.com
curl -i google.com
# Post json file
curl -vX POST http://localhost:9095/post -d @t.json -H "Content-Type: application/json" -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIiwiaWF0IjoxNTUxNDEyODY2LCJleHAiOjE1NTIwMTc2NjZ9.V6ZT8L_r_arIlxtRHul-FxKt4exErTkvNdYy7O_cR5A'
|
argument#
default argument#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| #!/usr/local/bin/bash
echo 'begin'
date
duration=${1-"3"} # default 3
sleep $duration
echo 'finish'
date
#begin
#2021年11月17日 星期三 12时05分52秒 CST
#finish
#2021年11月17日 星期三 12时05分55秒 CST
#~ took 3s
|
loop#
bash 提供 for和while两种循环控制
for#
1
2
3
4
5
6
7
8
9
10
| # for in
for i in abc.s{1..1000}; do
echo $i
done
# for arguments
./for.sh x y z sdf{1..4} 1 9
#for a; do
# echo $a
#done
|
while (read)#
1
2
3
4
5
6
7
| while read -r h; do
echo -n $h
done
#❯ bash read-pwds.sh
#abcde
#abcdexyz
#xyz%
|
macos#
osascript#

1
2
3
4
5
6
7
8
9
| #!/bin/sh
#
# must use sh for `at` command
#!/usr/bin/osascript
#display notification "Lorem ipsum dolor sit amet" with title "Title"
# https://apple.stackexchange.com/questions/57412/how-can-i-trigger-a-notification-center-notification-from-an-applescript-or-shel/115373#115373
osascript -e 'display notification "吃武汉热干面啦" with title "米西米西" '
|