什么是Shell编程

时间:2021-08-10 14:08来源:未知 作者:中博IT教育

Shell 是一类应用程序的统称,该类应用程序负责连接用户和 Linux 内核,让用户能够更加高效、安全、低成本地使用 Linux 内核来控制计算机硬件。 具体来说,linux系统上自带多种shell程序
Shell 是一类应用程序的统称,该类应用程序负责连接用户和 Linux 内核,让用户能够更加高效、安全、低成本地使用 Linux 内核来控制计算机硬件。
 
具体来说,linux系统上自带多种shell程序
 
[root@localhost ~]# chsh -l
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash
/bin/tcsh
/bin/csh
通常用户登录成功后执行的shell程序为:/bin/bash
 
[root@localhost ~]# head -1 /etc/passwd
root:x:0:0:root:/root:/bin/bash
其实,shell程序例如bash的本质就是一个解释器,shell本身就是一门解释型、弱类型、动态语言,与python相对应,Python属于解释型、强类型、动态语言,我们平时登录成功一个用户后进入的就是bash解释器的交互式环境,我们敲的命令其实都属于shell这门语言的语法
 
图片图片
 
2、为何要用shell
 
那还用说吗,一些日常的运维工作自动化、配合计划任务威力无穷,彻底解放双手,你说它不香吗?例如
 
拉取最新代码(git pull)
 
编译打包
 
上传并部署到远程服务器
 
 
 
3、Shell VS python
 
shell语言
 
Shell 脚本的优势在于处理偏操作系统底层的业务,例如,Linux 内部的很多应用(有的是应用的一部分)都是使用 Shell 脚本开发的,因为有 1000 多个 Linux 系统命令为它作支撑,特别是 Linux 正则表达式以及三剑客 grep、awk、sed 等命令。
 
对于一些常见的系统脚本,使用 Shell 开发会更简单、更快速,例如,让软件一键自动化安装、优化,监控报警脚本,软件启动脚本,日志分析脚本等,虽然 Python 也能做到这些,但是考虑到掌握难度、开发效率、开发习惯等因素,它们可能就不如 Shell 脚本流行以及有优势了。对于一些常见的业务应用,使用 Shell 更符合 Linux 运维简单、易用、高效的三大原则。
python语言
 
Python 是近几年非常流行的语言,它不但可以用于脚本程序开发,也可以实现 Web 程序开发(知乎、豆瓣、YouTube、Instagram 都是用 Python 开发),甚至还可以实现软件的开发(大名鼎鼎的 OpenStack、SaltStack 都是 Python 语言开发)、游戏开发、大数据开发、移动端开发。
 
现在越来越多的公司要求运维人员会 Python 自动化开发,Python 也成了运维人员必备的技能,每一个运维人员在熟悉了 Shell 之后,都应该再学习 Python 语言。
 
Python 语言的优势在于开发复杂的运维软件、Web 页面的管理工具和 Web 业务的开发(例如 CMDB 自动化运维平台、跳板机、批量管理软件 SaltStack、云计算OpenStack 软件)等。
二 bash解释器特性
启动操作系统后,linux系统会默认提供5个操作终端(multics=》unix=》。。。=》linux),可以用Ctrl + Alt + Fn(n=1,2,3,4,5...)快捷键切换,我们进入任意终端后输入账号密码登录用户后,就会执行该用户在/etc/passwd文件中指定的解释器程序,然后进入解释器的交互式环境
 
[root@localhost ~]# head -1 /etc/passwd
root:x:0:0:root:/root:/bin/bash  # 最后一个字段就是指定的解释器程序
何为交互式环境???
 
1、我们为解释器输入指令,解释器解释执行(调用操作系统接口执行)然后后给我们返回结果,这就叫交互
 
2、进入解释器交互式环境后普通用户的提示符是$,管理用户是#
 
3、shell命令的基本格式/语法格式:命令 选项 参数
命令优先级从高到低
 
==> alias
  ==> Compound Commands
    ==> function
      ==> build_in
        ==> hash
          ==> $PATH
            ==> error: command not found
                
                
#1、alias别名
可以用alias查看
可以用命令来制作:alias 别名="命令 选项 参数"
 
#2、Compound Commands复合命令
复合命令指的是能够将一组命令封装到一个代码块里的命令,例如if、for、while等
 
#3、function函数
 
#4、build in内建命令
可以用type查看,或者用man builtin
[root@egon ~]# type cd
cd 是 shell 内嵌
 
#5、hash
当别名和内部命令都搜到不到命令时,会检索$PATH中的路径
[root@egon ~]# sed -n 's/:/\n/gp' <<< $PATH
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/root/bin
 
但是$PATH中包含的路径太多了,而且每个路径中的可执行文件也很多
如果每次都要搜索每个路径下的所有可执行文件,显然是不明智的
为了减少$PATH的搜索,上一次搜索的内容能够被下一次执行重用
bash对从$PATH中搜索得出的外部命令建立一个hash表,用于缓存
这个缓存是会话级别独立拥有的.不可以对其他终端共享,因为每个用户的$PATH可能不同
[root@egon ~]# hostname  # 执行一次$PATH中的命令,linux系统就会将其缓存起来
egon.xxx.com
[root@egon ~]# hash      # 可以查看hash表的缓存
命中 命令
   2 /usr/bin/hostname
   1 /usr/bin/sed
   2 /usr/bin/man
   1 /usr/bin/ls
[root@egon ~]# hash -r   # 也可以清空掉
[root@egon ~]# hash
hash: 哈希表为空
    
#6、$PATH
 
 
================优先级验证=================
=====alias > Compound Commands > function======
#(1) 设置
[root@egon ~]# alias if="ls -l"
[root@egon ~]# function if(){
> echo "123"
> }
 
#(2) 验证alias的优先级最高
[root@egon ~]# if  
总用量 12
-rw-r--r-x. 1 root root 44 8月  13 19:36 1.sh
-rw-r--r-x. 1 root root 44 8月  13 19:36 2.sh
-rw-r--r-x. 1 root root 44 8月  13 19:37 3.sh
    
#(3) 取消别名,验证复合命令优先级>function
[root@egon ~]# unalias if 
[root@egon ~]# if  # 执行的是复合命令而不是函数
 
===========function > buitin=========
#(1) 设置
[root@egon ~]# function cd(){
> echo "自定义函数cd"
> }
[root@egon ~]# 
[root@egon ~]# type cd
cd 是函数
cd () 
    echo "自定义函数cd"
}
#(2) 验证
[root@egon ~]# cd  # 执行的是函数
自定义函数cd
 
 
===========buitin > hash > $PATH=========
#(1)最开始hash表内是没有任何命令的,优先级:builtin > $PATH
[root@egon ~]# unset cd
[root@egon ~]# type cd
cd 是 shell 内嵌
[root@egon ~]# cat /usr/bin/cd
#!/bin/sh
echo "这是PATH内的一个cd脚本"
[root@egon ~]# chmod +x /usr/bin/cd
[root@egon ~]# cd # 执行的是内置命令,而不是$PATH下的脚本cd
 
[root@egon ~]# cp /usr/bin/cd /usr/bin/hahaha
[root@egon ~]# hahaha 
这是PATH内的一个cd脚本
[root@egon ~]# 
 
#(2)后来hash表中有命令,但它缓存的是$PATH中的命令,说白了,与$PATH都是一样的东西,内置命令的优先级肯定高于hash
 
# (3) 优先级hash>$PATH
[root@egon ~]# hash -r
[root@egon ~]# hostname
egon.xxx.com
[root@egon ~]# hash 
命中 命令
   1 /usr/bin/hostname
[root@egon ~]# hostname
egon.xxx.com
[root@egon ~]# hash  # 缓存命中2次
命中 命令
   2 /usr/bin/hostname
bash的特性
 
1、交互式环境下:命令和文件路径自动补全(使用tab键)
 
2、交互式环境下:命令历史记录
 
上下键翻阅
 
!历史命令编号
 
!命令前缀字符
 
!$上一条命令的参数
 
ll -dl !$
!!执行最后一条命令
 
3、别名功能
 
alias、unalias、\命令
 
4、前后台作业: &、nohup、^c、^z、bg %1、fg %1、kill %3、screen
 
# 示例1
sh-3.2# sleep 15  # ctrl+z暂停程序
^Z
[1]+  Stopped(SIGTSTP)        sleep 15
sh-3.2# jobs
[1]+  Stopped(SIGTSTP)        sleep 15
sh-3.2# bg %1  # 后台运行
[1] sleep 15 &
sh-3.2# jobs
[1]+  Running                 sleep 15 &
sh-3.2# fg %1  # 前台运行
sleep 15
sh-3.2# 
 
# 示例2:
sh-3.2# cat a.sh 
sleep 15 && echo 123
 
sh-3.2# sh a.sh  # 暂停
^Z
[1]+  Stopped(SIGTSTP)        sh a.sh
sh-3.2# bg %1  # 后台运行
[1] sh a.sh &
sh-3.2# fg %1  # 前台运行,也可以kill %1杀死
sh a.sh
123
5、输入输出重定向:
 
0、1、2
 
>、>>、2>、2>>、&>、cat >file1 <<EOF
 
6、支持管道:|
 
7、一行连接多条命令
 
;:左边的命令执行无论是否成功都会执行右边
 
&&:左边的命令执行成功才会执行右边
 
make && make install
||:左边的命令执行失败才会执行右边
 
[ -d /home/egon ] || mkdir -p /home/egon
8、支持通配符操作,例如*、?、[]、\等,后续我们将会详细介绍
 
三 元字符
元字符指的是能够被shell解释的特殊字符,每一特殊字符都有其特殊含义
 
1、`` 与$():取命令的结果
 
[root@localhost ~]# echo `pwd`
/root
[root@localhost ~]# echo $(pwd)
/root
 
不一样的地方在于$()可以嵌套,而``不能嵌套
[root@localhost ~]# echo $(ls $(pwd))
 
# 练习
[root@aliyun test]# touch $(date +%F)_bak.tar.gz
[root@aliyun test]# ls
2020-08-24_bak.tar.gz
2、~家目录
 
3、.与..
 
4、!调用历史命令、取反
 
# 1、调用历史命令
[root@egon ~]# !1066
[root@egon ~]# !ls  # 匹配最近的一次历史命令
 
# 2、取反1:对命令的结果取反
[root@egon ~]# ! pwd
/root
[root@egon ~]# echo $?
1
 
# 3、取反2:效果与^雷同
[root@localhost ~]# touch /test/{1.txt,2.txt,a.txt,aaa_bbb.txt}
[root@localhost ~]# find /test ! -name 1.txt
/test
/test/2.txt
/test/a.txt
/test/aaa_bbb.txt
 
[root@localhost ~]# ls /test/[!0-9].txt  # .txt前只有一个字符,但是非数字
/test/a.txt
[root@localhost ~]# ls /test/[^0-9].txt  # .txt前只有一个字符,但是非数字
/test/a.txt
 
[root@aliyun test]# ls -a /etc/skel/.[!.]*
5、@无特殊意义
 
6、#注释
 
4、$取变量值
 
[root@localhost ~]# x=1
[root@localhost ~]# echo $x
1
5、%、-、+运算符,注意%可以与jobs配合“kill %工作号”杀后台进程。-减号还有区间及cd -回到上一级的意思
 
# 数学运算
# 1、bc是比较常用的linux计算工具了,而且支持浮点运算:
[root@localhost ~]# res=`echo 1+1 | bc`
[root@localhost ~]# echo $res
2
 
[root@localhost ~]# res=`echo 10 % 3 | bc`
[root@localhost ~]# echo $res
1
 
[root@localhost ~]# res=`echo 1.2+1.3|bc`
[root@localhost ~]# echo $res
2.5
 
[root@localhost ~]# res=`echo 5.0+3.0|bc`
[root@localhost ~]# echo $res
8.0
 
[root@localhost ~]# res=`echo "scale=2;5.0/3.0"|bc`
[root@localhost ~]# echo $res
1.66
 
[root@localhost ~]# res=`echo "scale=2;5.0/6.0"|bc`
[root@localhost ~]# echo $res
.83
 
# 2、expr不支持浮点数计算。而且要注意数字与运算符中的空格
[root@localhost ~]# res=`expr 5 / 3`  # 不支持浮点计算
[root@localhost ~]# echo $res
1
 
[root@localhost ~]# res=`expr 1+1`  # 注意:要有空格
[root@localhost ~]# echo $res
1+1
[root@localhost ~]# res=`expr 1 + 1`
[root@localhost ~]# echo $res
2
 
[root@localhost ~]# res=`expr 5 \* 3`  # 在expr中*号要转义才能用,否则报语法错误
[root@egon ~]# echo $res
15
 
# 3、$(()) 同expr,不支持浮点数运算
[root@localhost ~]# echo $((1+1))
2
[root@localhost ~]# echo $((1.0+2.0))
-bash: 1.0+2.0: 语法错误: 无效的算术运算符 (错误符号是 ".0+2.0")
            
# 4、$[]同expr以及$(()),不支持浮点运算
[root@localhost ~]# x=1
[root@localhost ~]# echo $[$x+1]
2
 
# 5、let 不支持浮点数运算,而且不支持直接输出,只能赋值
[root@localhost ~]# let res=1+1
[root@localhost ~]# echo $res
2
[root@localhost ~]# 
[root@localhost ~]# let res=50/5
[root@localhost ~]# echo $res
10
[root@localhost ~]# let c=1.3*3
-bash: let: c=1.3*3: 语法错误: 无效的算术运算符 (错误符号是 ".3*3"
                
[root@aliyun test]# x=1
[root@aliyun test]# let x+=10
[root@aliyun test]# echo $x
11
6、^同!一样
 
7、&后台运行
 
[root@localhost home]# echo "hello";sleep 3;echo "world" &
8、*任意多个字符
 
[root@localhost ~]# touch 1.txt 2.txt aa.txt aaa.txt
[root@localhost ~]# rm -rf *.txt
[root@localhost ~]# touch 1.txt 2.txt aa.txt aaa.txt a1c.txt
[root@localhost ~]# ls *.txt
1.txt  2.txt  a1c.txt  aaa.txt  aa.txt
9、()在子shell中执行
 
[root@localhost ~]# (x=1)
[root@localhost ~]# echo $x
 
应用
[root@localhost ~]# (umask 066;touch a.txt)  # umask的设置只在子shell中有效
[root@localhost ~]# ll a.txt 
-rw-------. 1 root root 0 8月  13 15:22 a.txt
[root@localhost ~]# touch b.txt
[root@localhost ~]# ll b.txt 
-rw-r--r--. 1 root root 0 8月  13 15:23 b.txt
10、_下划线:无特殊意义,可以用于名字的声明
 
[root@localhost ~]# tar -czvf  `date +%F_%H:%M:%S`_bak.tar.gz /etc/
11、=赋值,==判断相等性
 
[root@localhost ~]# [ 1 == 1 ]  # 条件1 == 1的左右两边必须有空格
[root@localhost ~]# echo $?    # 判断上一条命令的结果是否为真,0=》true
0
12、|管道:把一个进程的处理结果传递给另外一个进程
 
[root@localhost ~]# ps aux | grep python
 
 
|管道命令的作用,是将左侧命令的标准输出转换为标准输入,提供给右侧命令作为参数。但是,大多数命令都不接受标准输入作为参数,只能直接在命令行输入参数,这导致无法用管道命令传递参数。比如echo命令就不接受管道传参。
$ echo "hello world" | echo
xargs命令的作用,是将标准输入转为命令行参数,例如
$ echo "hello world" | xargs echo
hello world
 
[root@localhost ~]# find /home/ -type d -name "test*" |xargs ls
1.txt  2.txt  3.txt
[root@localhost ~]# ls /home/test
1.txt  2.txt  3.txt
13、\转义特殊字符
 
[root@localhost ~]# mkdir a\ b.txt  # 虽然可以,但不推荐
[root@localhost ~]# ll
总用量 0
drwxr-xr-x. 2 root root 6 8月  13 15:35 a b.txt
    
 
[root@localhost ~]# echo $RMB  # 默认会当成变量
 
[root@localhost ~]# echo '$RMB'  # 取消特殊意义
$RMB
[root@localhost ~]# echo \$RMB  # 取消特殊意义
$RMB
14、[]条件测试,后续会详细介绍
 
[root@localhost ~]# name="egon"
[root@localhost ~]# [ $name == "egon" ];echo $?
0
[root@localhost ~]# name="adf"
[root@localhost ~]# [ $name == "egon" ];echo $?
1
 
[root@localhost ~]# [ -d /test ];echo $?
0
[root@localhost ~]#
15、引号
 
''  强引用(在单引号中都视为普通字符)
" " 弱引用 (在双引号中保留变量)
 
[root@localhost ~]# x=111
[root@localhost ~]# echo "$x"
111
[root@localhost ~]# echo '$x'
$x
[roo
16、;与&&与||连接多条命令
 
[root@localhost home]# gagaga;ls  # 不论前一条命令运行成功与否,都会执行后续命令
bash: gagaga: 未找到命令...
egon
[root@localhost home]# gagaga && ls  # 只有前一条命令执行成功,才会执行后续命令
bash: gagaga: 未找到命令...
        
[root@localhost home]# ls /test || mkdir /test  # 前一条命令执行不成功才会执行后续命令
0.txt  1.txt  2.txt  3.txt  4.txt  5.txt  6.txt  7.txt  8.txt  9.txt
17、:空命令,真值
 
[root@egon ~]# :
[root@egon ~]# echo $?
0
18、/路径分隔符
 
19、{}循环列表
 
[root@localhost home]# touch /test/{0..9}.txt
[root@localhost home]# ls /test/
0.txt  1.txt  2.txt  3.txt  4.txt  5.txt  6.txt  7.txt  8.txt  9.txt
 
[root@localhost ~]# touch {1..3}{a..d}.txt
[root@localhost ~]# ls
1a.txt 1b.txt 1c.txt 1d.txt 2a.txt 2b.txt 2c.txt 2d.txt 3a.txt 3b.txt 3c.txt 3d.txt
 
[root@egon ~]# x=100
[root@egon ~]# echo ${x}%  # 控制变量名的范围
100%
[root@egon ~]# 
[root@egon ~]# echo $xrmb
 
[root@egon ~]# echo ${x}rmb
100rmb
20、重定向
 
> >> 输出重定向
< << 输入重定向
 
> 覆盖  >> 追加
[root@localhost home]# cat >> a.txt << EOF
> 111
> 222
> 333
> EOF
 
0标准输入、1标准正确输出、2标准错误输出,&标准正确和错误输出
[root@localhost home]# pwd 1>a.txt
[root@localhost home]# cat a.txt 
/home
[root@localhost home]# gagag 2>a.txt
[root@localhost home]# cat a.txt 
bash: gagag: 未找到命令...
[root@localhost home]# gagaga &>/dev/null
 
< << 输入重定向
[root@localhost ~]# mysql -uroot -p123 < bbs.sql
[root@localhost home]# grep root < /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
 
                        
[root@localhost home]# dd if=/dev/zero of=/a.txt bs=1M count=10
记录了10+0 的读入
记录了10+0 的写出
10485760字节(10 MB)已复制,0.024387 秒,430 MB/秒
[root@localhost home]# dd </dev/zero >/b.txt bs=1M count=10
记录了10+0 的读入
记录了10+0 的写出
10485760字节(10 MB)已复制,0.0202365 秒,518 MB/秒
 
[root@localhost home]# ll /a.txt 
-rw-r--r--. 1 root root 10485760 8月  13 16:02 /a.txt
[root@localhost home]# ll /b.txt 
-rw-r--r--. 1 root root 10485760 8月  13 16:03 /b.txt
21、?任意一个字符
 
[root@localhost ~]# ls ??.txt
aa.txt
[root@localhost ~]# ls a?c.txt
a1c.txt
[root@localhost ~]# rm -rf *.txt
22、范围中的任意一个字符 [12] [ac] [a-z] [0-9]
 
[root@localhost ~]# touch a1c a2c axc aXc axd
[root@localhost ~]# ls a?c
a1c  a2c  axc  aXc
[root@localhost ~]# ls a[1x]c
a1c  axc
[root@localhost ~]# ls a[a-z]c
axc  aXc
[root@localhost ~]# ls a[A-Z]c  # 不区分大小写
axc  aXc
[root@localhost ~]# ls a[x]c
axc
[root@localhost ~]# ls a[X]c
aXc
[root@localhost ~]# ls a[0-9]c
a1c  a2c
[root@localhost ~]# ls /dev/sd[a-z]*
/dev/sda  /dev/sda1  /dev/sda2  /dev/sda3  /dev/sdb1
(责任编辑:中博IT教育)

苏公网安备 32030302000649号