all-shell-scripts

我们在终端里敲命令是如何执行的 ?

如上图所示,shell是连接系统内核和外围应用程序的中间层,每个用户登陆到操作系统里都会被分配一个shell终端,不通的shell内置的一些东西略有不通,最常用的shell是bash

脚本语言的种类

sh
ksh
bash
csh
tcsh

查看系统支持的shell种类
cat /etc/shells

查看当前使用的shell种类
echo $SHELL

基本上系统默认的shell都是bash,这些shell有什么分别,大家可以百度下简单了解,我自己印象深刻的一个实际体验是,在macOS10.15+系统上,默认用的是zsh,这个东西的注释竟然不是#开头表示,瞬间没法用了

另外还有一些开发人员,喜欢自己配置zsh或fish,这些shell功能比较强大,补全功能多

因为不同的shell解析脚本的逻辑是略有不通的,为了尽可能让我们写的脚本在其它机器上都能如预期执行,建议执行脚本的时候用 bash name.sh 这样

5 Most Frequently Used Open Source Shells for Linux
https://www.tecmint.com/different-types-of-linux-shells/

解释器-单行-多行注释

1 脚本开头注明解释器
#!/bin/bash  OR  #! /bin/bash
不通语言的脚本在开头一般都会显示指定解释器名称
#! /bin/sh
#! /bin/bash
#! /usr/bin/expect
#! /usr/bin/perl
#! /usr/bin/env python

2 在脚本里添加单行注释
以 # 开头的内容被认为是注释

3 在脚本里添加多行注释
if false; then
comment line 1
comment line 2
comment line 3
fi

随机数

echo $RANDOM   取随机数 [0, 32767]
echo $RANDOM | md5sum

openssl rand -base64 8
openssl rand -base64 80

date +%s%N

head /dev/urandom | md5sum

echo $RANDOM | md5 | cut -c1-3

调试

################################### 1 echo ###########################################
大家都懂

################################## 2 cat -A ######################################
如果脚本是从windows里复制过来的,可能会有编码问题,可用用 cat -A file.sh 查看下有没有特殊字符,也可以用
dos2unix file.sh 转换下 (yum install dos2unix)

################################# 3 bash -x file.sh ##########################
显示执行的详细过程

4 bash -n file.sh  不执行脚本 仅查询是否有语法问题
5 bash -v file.sh  脚本的内容打印到屏幕上,并执行

######################## 6 set -x 与 set +x ####################################
如果我们的脚本很长,而我们只需要调试中间的一小段,此时如果用 bash -x file.sh ,这样调试整个脚本,输出的内容太多了,此时我们可以在脚本内部 set -x 开启详细输出,然后在适当的地方 set +x 取消详细输出
$ cat hello.sh
echo hhs 
pwd
i=666
set -x
echo $i
set +x
[dc2-user@10-255-20-218 ~]$ bash hello.sh
hhs
/home/dc2-user
+ echo 666
666
+ set +x

7 exit 在脚本适当的地方直接exit退出,方便调试

8 使用注释,暂时不care的注释掉

信号

类似CTRL+C这种快捷键,就是一种退出的信号,还有很多其它的信号,我们根据需要利用它们的功能

1 显示支持的信号列表
kill -l  OR trap -l
$ kill -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	

2 常见重要信号说明
HUP(1)         挂起,终端掉线或用户退出可引发 (nohup命令就利用了这个机制)
INT(2)         中断, CTRL+C 可引发
QUIT(3)        退出, CTRL+\ 可引发
TSTP(20)       CTRL+Z 可引发

3 trap 控制信号
trap "cmd1; cmd2" 信号名
trap 'echo hello' INT   (按下CTRL+C会触发打印hello)
trap ""  2   (这样执行之后,再按CTRL+C就没反应了,相当于屏蔽了CTRL+C的中断功能)
trap ":" 2   (恢复CTRL+C的功能)

4 中断信号与键盘的对应关系
stty -a

expect - 自动应答

Expect是一个用来实现自动交互功能的软件套件(Expect is a software suite for automating interactivetools),是基于TCL的脚本编程工具语言,TCL全拼为Tool Command Language,是一种急哦啊笨语言,由John Ousterhout创建,TCL功能很强大,经常被用于快速原型开发、脚本编程、GUI和测试等方面

yum install expect

如下操作是我们手动修改密码的过程,需要交互输入两次密码
# useradd xtest
# passwd xtest
Changing password for user xtest.
New password: Baidu123.com
Retype new password: Baidu123.com
passwd: all authentication tokens updated successfully.


下面是我们利用exp脚本自动交互的过程,* 表示通配符匹配
# cat xtest.exp
#! /bin/expect
spawn passwd xtest
expect "*password*"
send "Baidu123.com\n"
expect "*password*"
send "Baidu123.com\n"
expect eof
# expect xtest.exp 
spawn passwd xtest
Changing password for user xtest.
New password: 
Retype new password: 
passwd: all authentication tokens updated successfully.

linux expect详解(ssh自动登录) https://www.cnblogs.com/dion-90/articles/8570601.html

SHELL嵌套

Linux系统中只有一个根进程,其它进程都是这个进程的子进程,使用pstree -a可以看到这个进程

常见产生子shell的途径

##################### 带 & 提交后台作业 #########################
- 在shell中使用 & 可以产生子shell
- 由 & 产生的子shell可以直接引用父shell定义的变量
- 由 & 产生的子shell中定义的变量不能被父shell引用
- 在shell中使用 & 可以模拟实现类似其它程序的多线程并发功能

###################### 使用 管道 功能 ##########################
- 在shell中使用管道可以产生子shell
- 由管道产生的子shell可以直接引用父shell定义的本地变量
- 由管道产生的子shell中定义的变量不能被父shell引用
- 由管道产生的子shell不能异步执行,只能在执行完毕后才能返回到父shell环境

########################## () #######################
- 在shell中可以使用 () 产生子shell
- () 产生的子shell可以直接引用父shell定义的变量
- () 产生的子shell中定义的变量不能被父shell引用
- () 产生的子shell不能异步执行,只有在执行完毕后才能返回到父shell环境

########################## 通过调用外部shell脚本产生子shell #########################
- 同上

shell调用脚本的模式说明

1 fork 模式      bash file.sh
2 exec 模式      exec file.sh 与fork不同的是,exec后面的内容将不再执行
3 source 模式    source file.sh  不会产生新的shell

wait 并发编程

使用wait等待所有子任务结束
help wait

示例
写一个脚本实现判断192.168.1.0/24 网络里,当前在线的ip有哪些。
解答:
shell> cat tping.sh 
#!/bin/bash
for i in 172.16.1.{1..254}; do
{
    ping -c 2 $i &> /dev/null
    if [ $? -eq 0 ]; then
        echo $i is ok.
    fi
} &
done
wait

稳妥定位当前目录

workdir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd $workdir

给文字加上颜色

颜色展示语法
<Esc>[FormatCodem
其中<Esc>在命令行中可以表示成如下的三种形式:
    \e (推荐使用这种)
    \033
    \x1B
例如:
echo -e "\e[31mHello World\e[0m"
echo -e "\e[31mHello\e[0m World"

上面的案例中,其中蓝色和红色都是语法的固定格式,31代表从这里开始显示红色,0代表后面的文字恢复默认颜色。有点背景颜色的意思

文字颜色常用数字
31	Red	echo -e "\e[31mHello World\e[0m"
32	Green	echo -e "\e[32mHello World\e[0m"
33	Yellow	echo -e "\e[33mHello World\e[0m"
34	Blue	echo -e "\e[34mHello World\e[0m"
不建议在CentOS7中修改命令提示符的颜色,容易出现各种莫名其妙的故障。
参考资料
颜色参考帮组 man console_codes (CentOS6)
https://misc.flogisoft.com/bash/tip_colors_and_formatting


cat << 'EOF' > color-test.sh
RED='\e[31m'
GREEN='\e[32m'
END='\e[0m'

echo -e "${RED}我是红色${END}"
echo -e "${GREEN}我是绿色${END}"
EOF

source和sh的区别

.  filename [arguments]
source filename [arguments]
source和.的功能是一样的,.可以认为是source的的别名

使用source . sh执行脚本时,不需要脚本具有执行权限。
source一般用来更新系统的配置文件,比如/etc/profile,它是在当前shell环境中执行脚本,sh一般用来执行直接手写的脚本文件,会生成一个子shell环境去执行脚本。
./ 也可以执行脚本,需要脚本具有执行权限。

参考资料
https://www.cnblogs.com/pcat/p/5467188.html

set -x -e -u

#set -x  #verbose mode
#set -e  #Exit immediately if a command exits with a non-zero status
#set -u  #Treat unset variables as an error