Linux-Shell基础
Shell基础
Bash注释
Bash只支持单行注释,使用
#
开头的都被当作注释语句1
2
3单行注释
echo "Hello World" #注释通过Bash特性,可以实现多行注释
1
2
3
4
5
6
7
8:'
注释
'
: <<'EOF'
注释
EOF
Bash基本数据类型
Bash中基本数据类型只有字符串类型,连数值类型都没有
1
2
3都是字符串类型,可用declare -i声明为数值类型
[root@localhost ~]# echo hello
[root@localhost ~]# echo 123
Bash字符串串联
Bash中字符串的串联操作,可用将两段数据连接在一起
1
2
3[root@localhost ~]# echo xiaowang xiaowangc
xiaowang xiaowangc
[root@localhost ~]#
变量赋值和引用变量
1 | [root@localhost ~]# a=xiaowangc |
Shell可用使用未定义的变量和使用空变量
1
2
3
4
5
6[root@localhost ~]# echo $abc
[root@localhost ~]# a=
[root@localhost ~]# echo $a
[root@localhost ~]#变量引用
1
2
3
4[root@localhost ~]# a=666
[root@localhost ~]# echo $a 777
666 777
[root@localhost ~]#
命令替换
命令替换是值先执行id root,将id root的输出结果替换到$()
1
2[root@localhost ~]# echo $(id root)
uid=0(root) gid=0(root) groups=0(root)
算数运算
Shell可用使用$[]和$(())和let命令做算数运算
1
2
3
4
5
6
7
8
9
10
11[root@localhost ~]# a=10
[root@localhost ~]# echo $[a+3]
13
[root@localhost ~]# echo $((a+3))
13
[root@localhost ~]# echo $((1+1))
2
[root@localhost ~]# let a+3
[root@localhost ~]# let a=a+3
[root@localhost ~]# echo $a
13
退出状态码
每个命令执行之后都有对应的进程退出状态码,用来表示该进程是否正常退出。所以,在Shell中经常会使用特殊变量$?判断前台命令是否正常退出。
- 如果$?的值为:
- 为0,表示进程成功执行,即正常退出
- 非0,表示进程未成功执行,即非正常退出
- 非0退出状态码不一定表示错误,也可能是逻辑上正常的退出
- 在Shell脚本中,所有条件判断(比如if语句、while语句)都以0退出状态码表示True,以非0退出状态码表示False
Exit命令
exit命令可用于退出当前Shell进程。退出Shell终端、脚本等。
1 | exit |
后台执行命令&
在命令的结尾使用&符号,表示将这个命令放入后台执行。
1 | [root@localhost ~]# sleep 20 & |
多命令组合
Shell中有多种组合多个命令的方式
分号
1
2
3
4[root@localhost ~]# echo xiaowangc ; echo hello
xiaowangc
hello
[root@localhost ~]#&&
前者正确执行完毕并正常退出后,执行后者命令
1
2
3
4[root@localhost ~]# echo xiaowangc && echo hello
xiaowangc
hello
[root@localhost ~]#||;如果前者正确只执行前者,前者不正确执行后者(或)
1
2
3[root@localhost ~]# ping asdf && ping www.baidu.com
[root@localhost ~]# ping -c 4 www.baidu.com || ping abc逻辑结合
1
2
3
4
5
6
7
8
9
10命令1 && 命令2 && 命令3...
如果命令1正确执行则执行命令2,如果命令2正确执行则执行命令3
命令1 && 命令2 || 命令3...
如果命令1正确执行则执行命令2,如果命令1不正确执行则执行命令3
如果命令1正确执行则执行命令2,如果命令2不正确执行则执行命令3
命令1 || 命令2 && 命令3...
如果命令1正确执行则执行命令3
如果命令1不正确执行则执行命令2,如果命令2正确执行则执行命令3
多个命令组合
通过小括号或者大括号组合多个命令
1
2
3
4
5
6
7
8
9
10(命令1 ; 命令2 ; 命令3)
小括号是在子Shell中执行
{ 命令1 ; 命令2 ; 命令3}
{
命令1
命令2
命令3
}
大括号当前Shell中执行
重定向
标准输入、标准输出、标准错误,在Linux系统中,每个程序默认都会打开三个文件描述符
- fd=0:标准输入
- fd=1:标准输出
- fd=2:标准错误
Linux中一切皆文件,文件描述符也是文件:
- fd = 0:对应/dev/stdin文件
- fd = 1:对应/dev/stdout文件
- fd = 2:对应/dev/stderr文件
1 | [root@localhost ~]# ls -l /dev/std* |
重定向操作
1 | 1. > #格式化输出 |
还有一种操作经常将输出的目标文件指定为/dev/null。它是空设备,
1 | cat /dev/null > file #清空文件 |
cat命令
1 | [root@localhost ~]# cat -n /etc/fstab #-n选项,输出时带行号 |
here docer
输入重定向是<,除此之外还有<<,<<<
<<符号表示here doc,也就是后面表示跟着的是一篇文档。常用于多行数据输入
1
2
3
4
5
6
7
8
9
10
11
12
13
14[root@localhost ~]# cat << EOF #here doc作为标准输入被读取,然后被cat输出
hello
xiaowangc
EOF
hello
xiaowangc
[root@localhost ~]# cat << EOF > xiaowangc.txt #here doc的内容还会被cat格式化输出到指定文档
hello
xiaowangc
EOF
[root@localhost ~]# cat xiaowangc.txt
hello
xiaowangc
[root@localhost ~]#<<<表示here string。也就是说该符号后面是一个字符串
1
2
3
4
5
6
7
8
9
10
11
12[root@localhost ~]# cat <<< xiaowangc
xiaowangc
[root@localhost ~]# a=11111
[root@localhost ~]# cat <<< $a
11111
[root@localhost ~]# cat <<< "xiaowangc$a" #使用双引号时会进行替换
xiaowangc11111
[root@localhost ~]# cat <<< 'xiaowangc$a' #使用单引号时不会进行替换
a
[root@localhost ~]#
管道
每一个竖线”|“代表一个管道,第一个命令的标准输出会放进管道,第二个命令会从管道中读取进行处理
1 | [root@localhost ~]# ps -aux | grep sshd |
让grep既从/etc/fstab读取数据,也从管道中读取数据
1 | [root@localhost ~]# ps aux | grep "#" /etc/fstab /dev/stdin |
tee命令
tee命令可以将标准输入复制到标准输出和0或多个文件中。tee的作用是数据多重定向
1 | [root@localhost ~]# echo hello | tee /tmp/xiaowangc /tmp/xiaowc | cat |
条件测试语句
test命令或Bash内置命令[ ]可以做条件测试,如果测试的结果为True,则退出的状态码为0
这些条件测试常用在if、while语句中
true和false命令
true命令返回true,退出码为0
false命令返回false,退出码非0
1
2
3
4
5
6
7[root@localhost ~]# true
[root@localhost ~]# echo $?
0
[root@localhost ~]# false
[root@localhost ~]# echo $?
1
[root@localhost ~]#文件类测试
条件表达式 含义 -e 判断文件是否存在 -f 判断文件是否存在且为普通文件 -b 判断文件是否存在且为块设备 -c 判断文件是否存在且为字符设备 -S 判断文件是否存在且为套接字文件 -p 判断文件是否存在且为命令管道文件 -l 判断文件是否存在且为一个链接文件 -d 判断文件是否存在且为普通目录 文件属性类测试
条件表达式 含义 -r 文件是否存在且当前用户可读 -w 文件是否存在且当前用户可写 -x 文件是否存在且当前用户可执行 -s 文件是否存在且为非空文件 -N 文件是否存在,且上次read后是否被modify 两个文件之间的比较
条件表达式 含义 file1 -nt file2 判断file1是否比file2新 file1 -ot file2 判断file1是否比file2旧 file1 -ef file2 判断file1与file2是否为同一文件 数值大小比较
条件表达式 含义 int1 -eq int2 两个数值相等 int1 -ne int2 两个数值不相等 int1 -gt int2 n1大于n2 int1 -lt int2 n1小于n2 int1 -ge int2 n1大于等于n2 int1 -le int2 n1小于等于n2 字符串比较
条件表达式 含义 -z str 判断字符串是否为空,返回true str or -n str 判断字符串是否为空,返回falsh str1 = str2 or str1 == str2 判断str1和str2是否相同,相同则返回true str1 != str2 判断str1是否不等于str2 str1 > str2 判断str1是否大于str2 str1 < str 判断str1是否小于str2 逻辑运算符
条件表达式 含义 -a or && 两表达式同时为true才为true -o or || 两表达式任何一个为true则为true ! 对表达式取反 () 更改表达式优先级
if语句
1 | if 条件判断式1; then |
实例:
1 | ! /bin/sh |
case
case用于确定的分支判断。
实例:
1 | ! /bin/bash |
for循环
两种for循环结构:
1 | 第一种 |
while循环
1 | while 测试条件; |
无限循环的写法
1 | while : |
Shell函数
Shell函数可以当作命令一样执行,它是一个或多个命令的组合结构体。
1 | Shell函数的几种语法格式 |
函数定义后,可以直接使用函数名来进行调用,同时可以向函数传递0个或多个参数
1 | 不传递参数 |
- 在函数中,那些位置变量将具有特殊的含义:
- $1、$2、$3…:传递给函数的第一个参数保存在$1中,第二个参数保存在$2中,以此类推
- $@、$*:保存所有参数,各参数使用空格分隔
- 不用双引号包围时,两者没区别
- 使用双引号包围时,$@的各个元素都被双引号包围,$*的所有元素一次性被双引号包围
local在函数里定义局部变量
return语句可以来定义函数的返回值
实践:分析一段Shell脚本
1 | 1 #!/bin/bash |
分析
1 | 不要被那么多代码量给吓到了,我们慢慢来分析 |
主函数
1 | function main(){ |
prepare_check函数
1 | function prepare_check() { |
主函数
1 | function main(){ |
prepare_install函数
1 | function prepare_install() { |
install_soft函数
1 | function install_soft() { |
prepare_install函数
1 | function prepare_install() { |
主函数
1 | function main(){ |
get_installer函数
1 | function get_installer() { |
主函数
1 | function main(){ |
config_installer函数
1 | function config_installer() { |
主函数
1 | function main(){ |
记一次MySQL-Shell学习
日志记录函数
1 | mysql_log() { |
文件变量函数
1 | file_env() { |
检测文件本身函数
1 | _is_sourced() { |
进程初始化文件函数
1 | docker_process_init_files() { |
检测配置函数
1 | mysql_check_config() { |
获取配置函数
1 | mysql_get_config() { |
套接字函数
1 | mysql_socket_fix() { |
临时启动服务函数
1 | docker_temp_server_start() { |
停止临时服务函数
1 | docker_temp_server_stop() { |
检查密码函数
1 | docker_verify_minimum_env() { |
创建数据库文件函数
1 | docker_create_db_directories() { |
初始化数据库目录函数
1 | docker_init_database_dir() { |
设置环境变量
1 | docker_setup_env() { |
执行SQL脚本函数
1 | docker_process_sql() { |
初始化数据库函数
1 | docker_setup_db() { |
回显密码函数
1 | _mysql_passfile() { |
标志ROOT过期函数
1 | mysql_expire_root_user() { |
检查是否包含导进程停止的参数函数
1 | _mysql_want_help() { |
主函数
1 | _main() { |
入口
1 | if ! _is_sourced; then |
分析脚本
判断脚本的运行方式
1 | if ! _is_sourced; then # _is_sourced为假则开始运行主函数 |
1 | _is_sourced() { |
进入主函数
1 | _main() { |
检查是否包含导进程停止的参数函数
1 | _mysql_want_help() { |
记录日志函数
1 | mysql_note() { |
检查配置函数
1 | mysql_check_config() { |
设置环境变量函数
1 | docker_setup_env() { |
创建数据库目录函数
1 | docker_create_db_directories() { |