Shell教程—Shell入门
Shell 是一个用 C 语言编写的命令解释器(command interpreter),是Unix操作系统的用户接口,它是用户使用 Linux 的桥梁。 Shell 既是一种命令语言,又是一种程序设计语言。 Shell 是指一种应用程序,这个应用程序提供了一个界面, 用户通过这个界面访问操作系统内核的服务。下图所示用户、shell和操作系统的关系:

Shell 脚本(shell script),是一种为 shell 编写的脚本程序,shell 和 shell script 是两个不同的概念。Shell 编程跟JavaScript、php编程一样,只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就可以了。
一、Shell的种类
Linux 的 Shell 种类众多,我们可以使用命令cat /etc/shells
查看系统中安装的shell。通常操作系统内核(kernel)与shell是独立的套件,而且都可被替换。不同的操作系统使用不同的shell,同一个kernel之上可以使用不同的shell。常见的shell分为两大主流:
sh
- Bourne Shell(/usr/bin/sh或/bin/sh),Solaris,hpux默认shell
- Bourne Again Shell(/bin/bash),Linux系统默认的shell
csh
- C Shell(/usr/bin/csh)
- K Shell(/usr/bin/ksh)
-
Shell for Root(/sbin/sh)
Bourne Again Shell,由于易用和免费,Bash 在日常工作中被广泛使用。同时,Bash 也是大多数Linux 系统默认的 Shell。
查看当前系统使用的shell—echo $SHELL
二、Shell环境变量定义
1、临时环境变量
所谓临时变量是指在用户在当前登陆环境生效的变量,用户登陆系统后,直接在命令行上定义的环境变量便只能在当前的登陆环境中使用。当退出系统后,环境变量将不能下次登陆时继续使用。
2、将环境变量永久生效
通过将环境变量定义写入到配置文件中,用户每次登陆时系统自动定义,则无需再到命令行重新定义。定义环境变量的常见配置文件如下:
- /etc/profile 针对系统所有用户生效,此文件应用于所有用户每次登陆系统时的环境变量定义
- $HOME_name/.bash_profile 针对特定用户生效,$HOME为用户的宿主目录,当用户登陆系统后,首先继承/etc/profile文件中的定义,再应用$HOME/.bash_profile文件中的定义。
3、系统预定义的环境变量
系统环境变量对所有用户有效,如:PATH、HOME、SHELL、PWD等等,如下用echo命令打印上述的系统环境变量:
三、Shell脚本编程基本概念
1、shell脚本的格式
一个shell脚本通常包含如下部分:
首行
第一行内容在脚本的首行左侧,表示脚本将要调用的shell解释器,比如 #!/bin/bash
,就表示要代调用Bourne Again Shell解释器来执行shell脚本
#!
符号,英文名叫Shebang ([ʃɪˈbæŋ]),没有中文名。该符号能够被内核识别成是一个脚本的开始,这一行必须位于脚本的首行,/bin/bash是bash程序的绝对路径,在这里表示后续的内容将通过bash程序解释执行。
注释
注释符号#
放在需注释内容的前面。
内容
任何可执行的Linux命令以及shell编程的语法关键字
2、赋予shell脚本的执行权限
在Linux中创建的一个文件默认是没有执行权限的,包括shell脚本
没有执行权限是不能被执行的,需要我们给他权限:chmod 755 文件名 或 chmod +x 文件名
3、shell脚本的执行
(1)输入脚本的绝对路径或相对路
#绝对路径,在任何目录下都可以正常执行指定脚本
/usr/scripts/check-network.sh
#只有在脚本所在目录中执行命令才可以正确执行
./check-network.sh
(2)bash或sh +脚本名
#指定了bash之后,在shell脚本中第一行的那句#!/bin/bash就没有用了
bash /usr/scripts/check-network.sh
# 同理
sh /usr/scripts/check-network.sh
注:当脚本没有x权限时,root和文件所有者通过该方式可以正常执行。
(3)在脚本的路径前再加". " 或source
上面两种执行shell脚本的方法都是在子shell中执行的,没有在当前shell中执行,当我们需要在当前shell执行shell的时候,我们就需要使用这种方法。
#下面使用两种不同的执行方式
./usr/scripts/goto-usrlocal.sh
source /usr/scripts/goto-usrlocal.sh 或 . /usr/scripts/goto-home.sh
goto-usrlocal.sh脚本的内容如下:
#!/bin/bash
cd /usr/local
ls -l
一张图说明差别:
区别:第一种和第二种会新开一个bash,不同bash中的变量无法共享。但是使用. ./脚本.sh 这种方式是在同一个shell里面执行的。
四、Shell变量
变量是shell传递数据的一种方式,用来代表每个取值的符号名。当shell脚本需要保存一些信息时,如一个文件名或是一个数字,就把它存放在一个变量中。
1、变量设置规则:
(1)变量名称可以由字母,数字和下划线组成,但是不能以数字开头,环境变量名建议大写,便于区分。
(2)在bash中,变量的默认类型都是字符串型,如果要进行数值运算,则必须指定变量类型为数值型。
(3)变量用等号连接值,等号左右两侧不能有空格。
(4)变量的值如果有空格,需要使用单引号或者双引号包括。
2、 变量分类
(1)自定义变量
用户自定义的变量由字母或下划线开头,由字母,数字或下划线序列组成,并且大小写字母意义不同,变量名长度没有限制。
- 定义变量:变量名=变量值变量名必须以字母或下划线开头,区分大小写,ip1=192.168.2.115
- 引用变量:
$变量名或${变量名}
- 查看变量:echo $变量名或${变量名}
- 取消变量:unset 变量名
- 作用范围:在当前shell有效
示例:
#!/bin/bash
#1、显示直接赋值的变量
#Shell中的变量没有数据类型(或者说Shell中的变量默认就是字符串类型,因此当字符串中间有空格的时候需要用双引号括起来)
a=123
b=789
status="status is ok\!"
#2、通过语句给变量赋值
# 计算a+b的值
let c=a+b
#这一句的作用就是把把/usr/local中的文件名循环的取出来
for file in $(ls /usr/loccal)
在定义或引用变量的时候要特别注意: (1) ""
和''
两个引号的作用不同,双引号是弱引用,内部可以使用变量;单引号是强引用,内部无法使用变量。

(2)``
,反引号的作用是命令替换,作用等价于$()
,写在它们之中的命令会被优先执行。

(2)系统环境变量
保存和系统操作环境相关的数据。HOME、HOME、PWD、SHELL、SHELL、USER等等,可以使用env命令查看当前系统定义的所用系统变量,对于这些系统环境变量在我们编写shell脚本的时候可以直接使用。
- 定义环境变量:
#方法一:
export variable_name=xxxx
#方法二:将自定义变量转换为环境变量
variable_name=xxxx
export variable_name
- 引用环境变量:
$变量名或${变量名}
- 查看环境变量:echo $变量名或${变量名}
- 取消环境变量:unset 变量名
- 环境作用范围:在当前shell和子shell有效
示例:
系统环境变量我们熟悉的比如配置Java的环境变量,在Linux系统中比如有个jdk1.8的JDK在/usr/local/java下,我们配置系统环境变量可以这么配置:
#定义一系列的变量
JAVA_HOME=/usr/local/java/jdk1.8
JRE_HOME=${JAVA_HOME}/jre
CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib
PATH=${PATH}:$JAVA_HOME/bin:$JRE_HOME/bin
#把变量转换为环境变量
export JAVA_HOME JRE_HOME CLASSPATH PATH
(3)位置参数变量
主要用来在执行命令的时候向脚本中传递参数或数据,变量名不能自定义,变量作用固定。
格式 | 含义 |
---|---|
$n | n为数字,0代表命令本身,0代表命令本身,$1-$9代表第1到第9个参数,10以上的参数需要用大括号包含,如${10}。 |
示例:
#!/bin/bash
a=$1
b=$2
#let几乎支持所有的运算,包括括号优先、++、--等;参数可以不需要$,就可取到值进行运算;支持方幂运算let "a=3**2";但只支持整数运算。
let c=$1+$2
echo "$1+$2=${c}"
要特别 注意的是,$0
表示的时shell脚本本生,在使用的时候要特别注意!!!
(4)预定义变量
预定义变量是Bash中已经定义好的变量,变量名不能自定义,变量作用也是固定的,我们也可以直接使用这些变量。
格式 | 含义 |
---|---|
$? | 执行上一个命令的返回值 执行成功,返回0,执行失败,返回非0(具体数字由命令决定) |
$$ | 当前进程的进程号(PID),即当前脚本执行时生成的进程号 |
$! | 后台运行的最后一个进程的进程号(PID),最近一个被放入后台执行的进程 & |
$* | 代表命令行中所有的参数,把所有的参数看成一个整体。以"112 … $n"的形式输出所有参数 |
$@ | 代表命令行中的所有参数,把每个参数区分对待。以"1""1""2" … "$n" 的形式输出所有参数 |
$# | 代表命令行中所有参数的个数。添加到shell的参数个数 |
(5)read命令
Linux read命令用于从标准输入读取数值。
read 内部命令被用来从标准输入读取单行数据。这个命令可以用来读取键盘输入,当使用重定向的时候,可以读取文件中的一行数据。
语法:
read [-ers] [-a aname] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] name
参数说明:
- -a 后跟一个变量,该变量会被认为是个数组,然后给其赋值,默认是以空格为分割符。
- -d 后面跟一个标志符,其实只有其后的第一个字符有用,作为结束的标志。
- -p 后面跟提示信息,即在输入前打印提示信息。
- -e 在输入的时候可以使用命令补全功能。
- -n 后跟一个数字,定义输入文本的长度,很实用。
- -r 屏蔽\,如果没有该选项,则\作为一个转义字符,有的话 \就是个正常的字符了。
- -s 安静模式,在输入字符时不再屏幕上显示,例如login时输入密码。
- -t 后面跟秒数,定义输入字符的等待时间。
- -u 后面跟fd,从文件描述符中读入,该文件描述符可以是exec新开启的。
示例:
#!/bin/bash
read -n1 -p "Shell script startup success!Do you want to continue[Y/N] " answer
case $answer in
Y | y)
echo -e "\n"
read -p "input two number: " num1 num2
let sum=${num1}+${num2}
echo -e "\n"
echo "${num1}+${num2}=${sum}";;
N | n)
echo -e "\nexit...bye!";;
*)
echo -e "\nerror input";;
esac
exit 0
脚本的功能很简单,就是先让用户输入是否据需执行脚本,如果输入的Y/y就据需执行,否则直接退出。当输入Y/y之后在让用户输入两个数字,之后输出两个数的和。
执行结果:
五、Shell数学计算
1、整数计算
(1)使用expr 命令进行计算
expr支持的操作符有: |、&、<、<=、=、!=、>=、>、+、-、*、/、%;expr支持的操作符中所在使用时需用\
进行转义的操作符有:|、&、<、<=、>=、>、*;只支持整数运算。另外,expr的操作数和操作符之间要有一个空格,并且返回的结果需要用``或者$()来获取。
#!/bin/bash
num1=300
num2=40
#做四则运算
echo $num1+$num2=$(expr $num1 + $num2)
echo $num1-$num2=$(expr $num1 - $num2)
echo $num1*$num2=$(expr $num1 \* $num2)
echo $num1/$num2=$(expr $num1 / $num2)
echo $num1%$num2=$(expr $num1 % $num2)
执行结果:
(2)使用$(())处理
使用$(())可以直接输出结果,并且在引用变量的时候可以不用加$符号,对于有些特殊的运算符也不需要转义。同样的,它只支持整型运算。
#!/bin/bash
num1=300
num2=40
#做四则运算
echo $num1+$nums=$((num1+num2))
echo $num1-$num2=$((num1-num2))
echo $num1*$num2=$((num1*num2))
echo $num1/$num2=$((num1/num2))
echo $num1%$num2=$((num1%num2))
执行结果:
(3)使用$[]运算
$[]将中括号内的表达式作为数学运算先计算结果再输出;对$[]中的变量进行访问时前面需要加$;$[]支持的运算符与let相同,但也只支持整数运算。
#!/bin/bash
num1=300
num2=40
#做四则运算
echo $num1+$num2=$[$num1+$num2]
echo $num1-$num2=$[$num1-$num2]
echo $num1*$num2=$[$num1*$num2]
echo $num1/$num2=$[$num1/$num2]
echo $num1%$num2=$[$num1%$num2]
echo $num1^2=$[$num1**2]
echo $num2^10=$[$num2**1
执行结果:
(4)使用let命令运算
let命令是这几个命令中我认为最好用的一个,因为他操作住够简单,而且支持几乎所有的运算符!!!包括括号优先、++、--等;参数可以不需要$,就可取到值进行运算;支持方幂运算let a=3**2";但依然只支持整数运算。
#!/bin/bash
num1=300
num2=40
#做自增\增减
let num1++
echo num1++=$num1
#做四则运算
let sum=num1+num2
let sub=num1-num2
let mul=num1*nunm2
let div=num1/num2
let mod=num1%num2
let power=num1**2
echo $num1+$num2=$sum
echo $num1-$num2=$sub
echo $num1*$num2=$mul
echo $num1/$num2=$div
echo $num1%$num2=$mod
echo $num1^2=$power
执行结果:
小试牛刀
写一个脚本监控当前系统的内存暂用百分比%。 Linux系统中查看系统内存使用情况的命令是free
,但是free打印出来的的信息有两行Mem和Swap,Mem就是系统内存的使用详情,于是我们需要使用grep命令只取Mem这一行的数据,之后在使用awk分别获取Mem一行中第2和3个数据(总的内存、已经使用的内存)把他们相除即可。
#!/bin/bash
# memory used size
let mem_use=$(free | grep '^Mem:' | awk '{print $3}')
echo mem_use=$mem_use
#total momory size
let mem_total=$(free | grep '^Mem:' | awk '{print $2}')
echo mem_total=$mem_total
let mem_percent=$((mem_use*100/mem_total))
echo "内存已经使用:$mem_percent"%
执行结果:
2、浮点数计算
(1)bc命令行计算器,可以进行整数运算和浮点数运算
使用bc可以通过scale指定精度,但是只有在除法的时候才有生效,其他运算都是安装原来有几位就输出几位;bc支持除了位操作的所有运算。
!/bin/bash
num1=100
num2=3.3
#整数运算
c=$(echo "$num1+300"|bc)
echo $c
#浮点数计算,使用scale指定小数的精确范围
d=$(echo "scale=3;$num1/$num2"|bc)
echo $d
执行结果:
(2)使用awk处理
Awk是Linux中一个处理文本文件的语言,是一个非常好用的文本分析工具,之所以叫AWK是因为其取了三位创始人Alfred Aho,Peter Weinberger, 和 Brian Kernighan 的 Family Name 的首字符。关于Awk详细的请参考我的另一篇博客Linux教程— awk命令或者自行上网查找资料。
#!/bin/bash
num1=100
num2=5.57
ant=$(awk -v a=$num1 -v b=$num2 'BEGIN{printf("%.2f",a*b)}')
echo $ant
执行结果:
awk的变量跟shell的变量是独立的,所以需要使用-v进行变量传递;支持输出格式化,根据实际需要进行格式化输出;awk内置有非常多的函数,比如log、sqr、cos、sin等等。