一、Shell概述
shell
是一个 **命令行解释器,**他接受应用程序/用户的命令,然后调用操作系统内核。
![image.png](https://img-blog.csdnimg.cn/img_convert/191fdfe3212208e4ef36f6643df8e720.png#clientId=uac785ca8-bc46-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=259&id=uf34225e4&margin=[object Object]&name=image.png&originHeight=324&originWidth=491&originalType=binary&ratio=1&rotation=0&showTitle=false&size=38512&status=done&style=none&taskId=u0b483c1d-8d89-4bff-8921-23028ec49c0&title=&width=392.8)
![image.png](https://img-blog.csdnimg.cn/img_convert/49642938735ff60bd2df83f30dfb6462.png#clientId=uac785ca8-bc46-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=151&id=ubf4e0cdd&margin=[object Object]&name=image.png&originHeight=189&originWidth=811&originalType=binary&ratio=1&rotation=0&showTitle=false&size=18492&status=done&style=none&taskId=u942f2243-af2c-457e-9744-e3880a9ea20&title=&width=648.8)
![image.png](https://img-blog.csdnimg.cn/img_convert/4d5f9e4fed18686792a0fa79e34e624c.png#clientId=uac785ca8-bc46-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=154&id=u629114aa&margin=[object Object]&name=image.png&originHeight=192&originWidth=937&originalType=binary&ratio=1&rotation=0&showTitle=false&size=31357&status=done&style=none&taskId=u1af011c5-c330-484b-ab34-2ec118520cf&title=&width=749.6)
其实说白了,我们常用的一些命令全是一些用C语言编写的一些二进制文件。
1.Linux提供的Shell解析器
![image.png](https://img-blog.csdnimg.cn/img_convert/7f7e7b249437ea6e60ffa92f83e70e29.png#clientId=uac785ca8-bc46-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=332&id=uda5e9147&margin=[object Object]&name=image.png&originHeight=415&originWidth=1006&originalType=binary&ratio=1&rotation=0&showTitle=false&size=27652&status=done&style=none&taskId=u852a2320-ffc8-41ad-a37e-4149bfd2b0d&title=&width=804.8)
2.bash和sh的关系
![image.png](https://img-blog.csdnimg.cn/img_convert/83d7abcc363b373014f7a01cb7cb5232.png#clientId=uac785ca8-bc46-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=178&id=u943b62f1&margin=[object Object]&name=image.png&originHeight=223&originWidth=942&originalType=binary&ratio=1&rotation=0&showTitle=false&size=24225&status=done&style=none&taskId=u921314bd-612d-4eab-9c54-463c685eed3&title=&width=753.6)
我们可以发现,其实 bash 和 sh 其实是一个东西
3.shell 其他解释器的一些简单介绍
那么大家一定很好奇,其他的一些 csh、tcsh、dash、zsh
等等又是什么呢?
ash
ash shell是由Kenneth Almquist编写的,Linux中占用系统资源最少的一个小shell,它只包含24个内部命令,因而使用起来很不方便
bash
bash是Linux系统默认使用的shell,它由Brian Fox和Chet Ramey共同完成,是Bourne Again Shell的缩写,内部命令一共有40个。
ksh
ksh是Korn shell的缩写,由Eric Gisin编写,共有42条内部命令。该shell最大的优点是几乎和商业发行版的ksh完全兼容,这样就可以在不用花钱购买商业版本的情况下尝试商业版本的性能了。
csh
csh是Linux比较大的内核,它由以William Joy为代表的共计47位作者编成,共有52个内部命令。该shell其实是指向/bin/tcsh这样的一个shell,也就是说,csh其实就是tcsh。
zch
zch是Linux最大的shell之一,由Paul Falstad完成,共有84个内部命令。如果只是一般的用途,是没有必要安装这样的shell的
dash
ubantu 用的是这个
因为这个有好多,我这里不依依介绍了,其实每个解释器都差不多,有的是一些扩展,有的是进行一定程度的精简。
那么如何查看当前环境的解释器呢?
![image.png](https://img-blog.csdnimg.cn/img_convert/fd51c66cf2a3a2e786a069c0354977cf.png#clientId=uac785ca8-bc46-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=106&id=udd1abd75&margin=[object Object]&name=image.png&originHeight=132&originWidth=585&originalType=binary&ratio=1&rotation=0&showTitle=false&size=9031&status=done&style=none&taskId=u93886eee-914a-4412-8fb4-c9ff907ff1a&title=&width=468)
二、开始学习Shell
第一个shell 脚本
[lighthouse@VM-24-12-centos workplace]$ touch hello_world.sh
[lighthouse@VM-24-12-centos workplace]$ vim hello_world.sh
[lighthouse@VM-24-12-centos workplace]$ ./hello_world.sh
bash: ./hello_world.sh: Permission denied
[lighthouse@VM-24-12-centos workplace]$
# 脚本的内容
#!/bin/bash
echo hello world
当脚本执行的时候我们发现这个脚本没有权限。通常情况下,我们给这个脚本增加可执行的权限就好了
[lighthouse@VM-24-12-centos workplace]$ chmod +x hello_world.sh
[lighthouse@VM-24-12-centos workplace]$ ls -l hello_world.sh
-rwxrwxr-x 1 lighthouse lighthouse 29 Jul 24 22:25 hello_world.sh
[lighthouse@VM-24-12-centos workplace]$
[lighthouse@VM-24-12-centos workplace]$ ./hello_world.sh
Hello world
[lighthouse@VM-24-12-centos workplace]$
现在我们解释下我们这个脚本的内容
#!bin/bash
是脚本解释器,专业术语叫 shebang
#!/bin/sh:使用 sh,即 Bourne shell 或其它兼容 shell 执行脚本
#!/bin/csh:使用 csh,即 C shell 执行
#!/usr/bin/perl -w:使用带警告的 Perl 执行
#!/usr/bin/python -O:使用具有代码优化的 Python 执行
#!/usr/bin/php:使用 PHP 的命令行解释器执行
echo hello world
echo /bin/bash 的内置函数 相当于 我们常用的print 。
[lighthouse@VM-24-12-centos workplace]$ type echo
echo is a shell builtin
[lighthouse@VM-24-12-centos workplace]$
shell 还有那些有趣的知识
如果执行一个shell 是不是必须加一个可执行的权限呢? 大家可以想一想
[lighthouse@VM-24-12-centos workplace]$ /bin/bash hello_world
Hello world
[lighthouse@VM-24-12-centos workplace]$ ls -l hello_world
-rw-rw-r-- 1 lighthouse lighthouse 30 Jul 24 22:35 hello_world
[lighthouse@VM-24-12-centos workplace]$ cat hello_world
echo Hello world
[lighthouse@VM-24-12-centos workplace]$
[lighthouse@VM-24-12-centos workplace]$ . hello_world
Hello World
[lighthouse@VM-24-12-centos workplace]$
[lighthouse@VM-24-12-centos workplace]$ cat hello_world
echo Hello World
[lighthouse@VM-24-12-centos workplace]$ source hello_world
Hello World
[lighthouse@VM-24-12-centos workplace]$
大家有没有发现,其实不用给执行可执行权限,不用给定 解释器,不用以 .sh
结尾。这个脚本其实也可以正常执行。
- 知识补充
[lighthouse@VM-24-12-centos workplace]$ python hello_world
Hello world
[lighthouse@VM-24-12-centos workplace]$ cat hello_world
print("Hello world")
[lighthouse@VM-24-12-centos workplace]$
[lighthouse@VM-24-12-centos workplace]$ chmod +x hello_world
[lighthouse@VM-24-12-centos workplace]$ ./hello_world
Hello world
[lighthouse@VM-24-12-centos workplace]$ cat hello_world
#!/usr/bin/python
print("Hello world")
[lighthouse@VM-24-12-centos workplace]$
其实不止 shell 脚本,其实所有的脚本类型语言全是这样的,知识点全是相通的。
shell 脚本之 变量
- 系统变量
常用的系统变量有 $HOME、$PWD、$SHELL、$USER等
[lighthouse@VM-24-12-centos workplace]$ echo $PWD
/home/lighthouse/workplace
[lighthouse@VM-24-12-centos workplace]$ echo $USER
lighthouse
[lighthouse@VM-24-12-centos workplace]$ echo $HOME
/home/lighthouse
[lighthouse@VM-24-12-centos workplace]$
# 这几个变量很重要,大家要牢记。
查看 当前的所有变量可用用 set
[lighthouse@VM-24-12-centos workplace]$ set |less
BASH=/usr/bin/bash
BASHOPTS=checkwinsize:cmdhist:complete_fullquote:expand_aliases:extglob:extquote:force_fignore:histappend:interactive_comments:login_shell:progcomp:promptvars:sourcepath
BASHRCSOURCED=Y
BASH_ALIASES=()
BASH_ARGC=()
BASH_ARGV=()
BASH_CMDS=()
- 如何设置变量
[lighthouse@VM-24-12-centos /]$ xiaoming=1
[lighthouse@VM-24-12-centos /]$ set |less |grep xiaoming
xiaoming=1
[lighthouse@VM-24-12-centos /]$ ps -f
UID PID PPID C STIME TTY TIME CMD
lightho+ 761731 2084694 0 23:12 pts/1 00:00:00 bash --login
lightho+ 762963 761731 0 23:17 pts/1 00:00:00 ps -f
[lighthouse@VM-24-12-centos /]$ echo $xiaoming
1
[lighthouse@VM-24-12-centos /]$ bash
[lighthouse@VM-24-12-centos /]$ ps -f
UID PID PPID C STIME TTY TIME CMD
lightho+ 761731 2084694 0 23:12 pts/1 00:00:00 bash --login
lightho+ 763008 761731 2 23:17 pts/1 00:00:00 bash
lightho+ 763121 763008 0 23:17 pts/1 00:00:00 ps -f
# 新起一个子进程
[lighthouse@VM-24-12-centos /]$ echo $xiaoming
# 子进程中无法获取到父进程的值
[lighthouse@VM-24-12-centos /]$
[lighthouse@VM-24-12-centos /]$ exit
exit
[lighthouse@VM-24-12-centos /]$ echo $xiaoming
1
[lighthouse@VM-24-12-centos /]$
# 父进程中仍然可以获取到值
[lighthouse@VM-24-12-centos /]$ unset xiaoming
[lighthouse@VM-24-12-centos /]$ echo $xiaoming
[lighthouse@VM-24-12-centos /]$
# 通过unset 可以撤销变量
[lighthouse@VM-24-12-centos /]$ xiaoming=1000
[lighthouse@VM-24-12-centos /]$ echo $xiaoming
1000
[lighthouse@VM-24-12-centos /]$ export xiaoming
[lighthouse@VM-24-12-centos /]$ bash
[lighthouse@VM-24-12-centos /]$ ps -f
UID PID PPID C STIME TTY TIME CMD
lightho+ 761731 2084694 0 23:12 pts/1 00:00:00 bash --login
lightho+ 763859 761731 0 23:22 pts/1 00:00:00 bash
lightho+ 763977 763859 0 23:22 pts/1 00:00:00 ps -f
[lighthouse@VM-24-12-centos /]$ echo $xiaoming
1000
[lighthouse@VM-24-12-centos /]$
通过以上的例子,我们不难发现其实对于 shell 变量我们不难发现,其实shell 变量其实是存在作用域的,全局变量在父shell 和子shell 中都可以访问到,局部变量只有在当前shell 中生效。
但是有一点需要注意:
[lighthouse@VM-24-12-centos /]$ bash
[lighthouse@VM-24-12-centos /]$ echo $xiaoming
1000
[lighthouse@VM-24-12-centos /]$ set|less|grep xiaoming
xiaoming=1000
[lighthouse@VM-24-12-centos /]$ xiaoming=2000
[lighthouse@VM-24-12-centos /]$ set|less|grep xiaoming
xiaoming=2000
[lighthouse@VM-24-12-centos /]$ export xiaoming
[lighthouse@VM-24-12-centos /]$ exit
exit
[lighthouse@VM-24-12-centos /]$ echo $xiaoming
1000
[lighthouse@VM-24-12-centos /]$
在子shell 中修改全局变量其实是不起作用的,也就是子shell 修改的全局变量只在子shell 中生效。
在明白了 全局变量和局部变量以后,我们再来思考下 前面说到的 source hello_world
到底做了什么
[lighthouse@VM-24-12-centos workplace]$ vim hello_world
[lighthouse@VM-24-12-centos workplace]$ cat hello_world
echo Hello World
a=1
[lighthouse@VM-24-12-centos workplace]$ echo $a
[lighthouse@VM-24-12-centos workplace]$ source hello_world
Hello World
[lighthouse@VM-24-12-centos workplace]$ echo $a
1
[lighthouse@VM-24-12-centos workplace]$
其实source 就是在当前的bash 中执行脚本!
在学习完局部变量后全局变量以后我们能用来干什么呢?
[lighthouse@VM-24-12-centos ~]$ pwd
/home/lighthouse
[lighthouse@VM-24-12-centos ~]$ ls -la |grep bash
-rw------- 1 lighthouse lighthouse 2617 Jul 24 23:48 .bash_history
-rw-r--r-- 1 lighthouse lighthouse 18 May 27 2021 .bash_logout
-rw-r--r-- 1 lighthouse lighthouse 140 Jul 24 23:43 .bash_profile
-rw-r--r-- 1 lighthouse lighthouse 375 Jul 24 23:55 .bashrc
[lighthouse@VM-24-12-centos ~]$
[lighthouse@VM-24-12-centos ~]$ cat .bash_profile
# .bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
# User specific environment and startup programs
[lighthouse@VM-24-12-centos ~]$ cat .bashrc
# .bashrc
# Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi
# User specific environment
if ! [[ "$PATH" =~ "$HOME/.local/bin:$HOME/bin:" ]]
then
PATH="$HOME/.local/bin:$HOME/bin:$PATH"
fi
export PATH
# Uncomment the following line if you don't like systemctl's auto-paging feature:
# export SYSTEMD_PAGER=
# User specific aliases and functions
[lighthouse@VM-24-12-centos ~]$
[lighthouse@VM-24-12-centos ~]$ cat .bashrc
# .bashrc
# Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi
# User specific environment
if ! [[ "$PATH" =~ "$HOME/.local/bin:$HOME/bin:" ]]
then
PATH="$HOME/.local/bin:$HOME/bin:$PATH"
fi
export PATH
sl # 增加小火车
# Uncomment the following line if you don't like systemctl's auto-paging feature:
# export SYSTEMD_PAGER=
# User specific aliases and functions
[lighthouse@VM-24-12-centos ~]$
效果图
![image.png](https://img-blog.csdnimg.cn/img_convert/75790a6503b6163c5606acd8eea83e9a.png#clientId=uae06d435-46ea-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=699&id=u491b9871&margin=[object Object]&name=image.png&originHeight=874&originWidth=1920&originalType=binary&ratio=1&rotation=0&showTitle=false&size=31970&status=done&style=none&taskId=uae80287f-4e1a-45a1-9ef7-877c47af1df&title=&width=1536)
每次进入都显示这个小火车。
接下来我们继续修改 .bashrc 文件,用来实现自动加载环境变量
[lighthouse@VM-24-12-centos /]$ hello_world
bash: hello_world: command not found...
[lighthouse@VM-24-12-centos /]$ vim ~/.bashrc
[lighthouse@VM-24-12-centos /]$ cat ~/.bashrc
# .bashrc
# Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi
# User specific environment
if ! [[ "$PATH" =~ "$HOME/.local/bin:$HOME/bin:" ]]
PATH="$HOME/workplace:$PATH"
then
PATH="$HOME/.local/bin:$HOME/bin:$PATH:"
fi
export PATH
#sl
# Uncomment the following line if you don't like systemctl's auto-paging feature:
# export SYSTEMD_PAGER=
# User specific aliases and functions
[lighthouse@VM-24-12-centos /]$ soure ~/.bashrc
bash: soure: command not found...
[lighthouse@VM-24-12-centos /]$ source ~/.bashrc
[lighthouse@VM-24-12-centos /]$ hello_world
Hello World
[lighthouse@VM-24-12-centos /]$ pwd
/
[lighthouse@VM-24-12-centos /]$
# 这样我们就实现了在任意的路径来执行我们的脚本。
$?的用法
$?
(功能描述:最后一次执行的命令的返回状态。如果这个变量的值为0,证明上一个命令正确执行;如果这个变量的值为非0(具体是哪个数,由命令自己来决定),则证明上一个命令执行不正确了。)
[lighthouse@VM-24-12-centos /]$ hello_world
Hello World
[lighthouse@VM-24-12-centos /]$ echo $?
0
[lighthouse@VM-24-12-centos /]$ sdfasd
bash: sdfasd: command not found...
[lighthouse@VM-24-12-centos /]$ echo $?
127
[lighthouse@VM-24-12-centos /]$
运算符
[lighthouse@VM-24-12-centos /]$ echo $[2+3]
5
[lighthouse@VM-24-12-centos /]$
- 条件判断
(1)两个整数之间比较
-eq等于(equal)-ne不等于(notequal)
-lt小于(lessthan)-le小于等于(lessequal)
-gt大于(greaterthan)-ge大于等于(greaterequal)
注:如果是字符串之间的比较,用等号“=”判断相等;用“!=”判断不等。
[lighthouse@VM-24-12-centos /]$ [ 23 -ge 22 ]
[lighthouse@VM-24-12-centos /]$ echo $?
0
[lighthouse@VM-24-12-centos /]$
(2)按照文件权限进行判断
-r有读的权限(read)
-w有写的权限(write)
-x有执行的权限(execute)
[lighthouse@VM-24-12-centos /]$ [ -x hello_world ]
[lighthouse@VM-24-12-centos /]$ echo $?
1
[lighthouse@VM-24-12-centos /]$ ls -l $HOME/workplace
total 4
-rwxrwxr-x 1 lighthouse lighthouse 21 Jul 24 23:52 hello_world
[lighthouse@VM-24-12-centos /]$
(3)按照文件类型进行判断
-e文件存在(existence)
-f文件存在并且是一个常规的文件(file)
-d文件存在并且是一个目录(directory)
[lighthouse@VM-24-12-centos /]$ [ -f hello_world ]
[lighthouse@VM-24-12-centos /]$ echo $?
1
[lighthouse@VM-24-12-centos /]$
流程控制
if-else
if ! [[ "$PATH" =~ "$HOME/.local/bin:$HOME/bin:" ]]
PATH="$HOME/workplace:$PATH"
then
PATH="$HOME/.local/bin:$HOME/bin:$PATH:"
fi
- case
[lighthouse@VM-24-12-centos workplace]$ vim case.sh
[lighthouse@VM-24-12-centos workplace]$ cat case.sh
#!/bin/bash
case $1 in
"1")
echo xiaoming
;;
"2")
echo xiaozhang
;;
*)
echo xiaowang
;;
esac
[lighthouse@VM-24-12-centos workplace]$ /bin/bash case.sh 1
xiaoming
[lighthouse@VM-24-12-centos workplace]$ /bin/bash case.sh 2
xiaozhang
[lighthouse@VM-24-12-centos workplace]$ /bin/bash case.sh 4
xiaowang
[lighthouse@VM-24-12-centos workplace]$
- for 循环
[lighthouse@VM-24-12-centos workplace]$ vim for.sh
[lighthouse@VM-24-12-centos workplace]$ cat for.sh
#!/bin/bash
sum=0
for((i=0;i<=$1;i++))
do
sum=$[$sum+$i]
done
echo $sum
[lighthouse@VM-24-12-centos workplace]$ for.sh 100
5050
[lighthouse@VM-24-12-centos workplace]$
- while 循环
[lighthouse@VM-24-12-centos workplace]$ cat while.sh
#!/bin/bash
i=0
while (( $i <= $1 ))
do
sum=$[$sum+$i]
i=$[$i+1]
done
echo $sum
[lighthouse@VM-24-12-centos workplace]$ while.sh 100
5050
[lighthouse@VM-24-12-centos workplace]$
- read 读取控制台输入
[lighthouse@VM-24-12-centos workplace]$ vim read.sh
[lighthouse@VM-24-12-centos workplace]$ chmod +x read.sh
[lighthouse@VM-24-12-centos workplace]$ read.sh
等待输入username:xiaowang
xiaowang
[lighthouse@VM-24-12-centos workplace]$ cat read.sh
#!/bin/bash
read -t 7 -p "等待输入username:" username
echo $username
[lighthouse@VM-24-12-centos workplace]$