系统相关
首页 > 系统相关> > Shell编程规范与变量

Shell编程规范与变量

作者:互联网

文章目录


前言

在一些复杂的Linux维护工作中,大量重复性的输入和交互操作不但费时费力,而且容易出错。
而编写一个恰到好处的shell脚本程序,可以批量处理,自动化的完成一系列维护任务,大大减轻管理员的负担。


一、Shell脚本概述

1.什么是Shell?

shell是一个命令解释器,它在操作系统的最外层,负责直接与用户进行对话,把用户的输入解释给操作系统,并处理各种各样的操作系统的输出结果,输出到屏幕反馈给用户。这种对话方式可是交互也可以是非交互式的,我们所输入的命令计算机是不识别的,这时就需要一种程序来帮助我们进行翻译,变成计算机能识别的二进制程序,同时又把计算机生成的结果返回给我们。

2.Shell的作用

常见的shell_解释器程序有很多种,使用不同的 Shell时,共内部指令、命令行提示符等力而会存在一些区别。通过 /etc/shells 文件可以了解当前系统所支持的shell脚本种类

[root@c7-1 ~]# cat /etc/shells 
/bin/sh         //是bash命令的软链接(己经被/bin/baah所替换)
/bin/bash		//基准于GNU的框菜下发E出的Shell

/sbin/nologin   
#nologin:奇怪的shell,这个shell可以让用户无法登录主机。bash ( /bin/bash)是目前大多数Linux版本采用的默认shell。

/usr/bin/sh   	//已经被bash所替换
/usr/bin/bash	//centos和redhat系统默认使用bash shell

/bin/tcsh		//csh的增强版,与csh完全兼容整合了csh,提供更多的功能。
/bin/csh		//已经被/bin/bash 所替换(整合C shell,提供更多的功能)
[root@c7-1 ~]# 

2.1 为什么系统上合法的shell要写入 /etc/shells 这个文件?

这是因为系统某些服务在运行过程中,会去检查用户能够使用的shells,而这些shell的查询就是借由 /etc/shells 这个文件

2.2 用户什么时候可以取得shell来工作?会取得哪一个shell?

当我登录的时候,系统就会给我shell让我来工作,而这个登录取得的shell就记录在 /etc/passwd 这个文件内。

2.3 用户的登陆Shell

不同的shell具备不同的功能,shell还决定了Linux中 默认的shell是/bin/bash,流行的shell有ash、bash、ksh、csh、zsh等,不同的shell都有自己的特点以及用途
目前大多数linux系统默认使用的是 bash shell默认登陆shell是/bin/bash,可以查看 /etc/passwd 文件里注明
这个shell是针对用户而言的,可以查看/etc/passwd里面的 最后的字段使用的是哪个shell,如果想要修改可以用 chnod -s或者chsh-s来重新指定

3.Shell脚本是什么

shell脚本就是说我们把原来 linux 命令或语句放在一个文件中,然后通过这个程序文件去执行时,我们就说这个程序为 shell脚本或shell程序;我们可以在脚本中输入一系统的命令以及相关的语法语句组合,比如变量,流程控制语句等,把他们有机结合起来就形成了一个功能强大的shell 脚本

4.Shell脚本能干什么

5.Shell脚本使用场景

在需要完成大量复杂、重复性的工作时,不需要在命令行重复执行命令,直接运行shell脚本即可,大大的节省了时间提高了效率


二、编写Shell脚本

1.Shell脚本的构成

 #!/bin/bash
#第一行为"#!/bin/bash",脚本中明(默认解释器)﹔表示此行以下的代码语句是通过/bin/bash程序来执行。


还有其他类型的解释器:
#!/ysr/bin/bash
#!/usr/bin/expect

注释信息:以"#"开头的语句表示为注释信息,被注释的语句在脚本运行时不会被执行

2.编写脚本代码

[root@c7-1 home]# vim test.sh

#!/bin/bash  
cd /boot		//切换到boot目录
pwd				//查看当前目录
ls -lh vml*		//查看所有vml(内核)文件

3.Shell脚本执行

3.1 方法一:当前路径下(绝对路径与相对路径)下执行脚本(要有执行权限)

[root@c7-1 home]# ./test.sh
-bash: ./test.sh: 权限不够
[root@c7-1 /]# /home/test.sh
-bash: /home/test.sh: 权限不够
[root@c7-1 home]# ls -lh
-rw-r--r--.  1 root root  38 9月   2 18:56 test.sh
#若不给test.sh文件权限则不能执行

[root@c7-1 /]# chmod +x /home/test.sh  //给test.sh可执行文件权限
[root@c7-1 home]# ls -lh
-rwxr-xr-x.  1 root root  38 9月   2 18:56 test.sh

[root@c7-1 home]# ./test.sh 
/boot
-rwxr-xr-x. 1 root root 5.7M 7月  22 01:24 vmlinuz-0-rescue-88592b0b2e2b49fab4e71eedc23b1998
-rwxr-xr-x. 1 root root 5.7M 8月  23 2017 vmlinuz-3.10.0-693.el7.x86_64
[root@c7-1 /]# /home/test.sh
/boot
-rwxr-xr-x. 1 root root 5.7M 7月  22 01:24 vmlinuz-0-rescue-88592b0b2e2b49fab4e71eedc23b1998
-rwxr-xr-x. 1 root root 5.7M 8月  23 2017 vmlinuz-3.10.0-693.el7.x86_64
#给完权限之后,才能执行

3.2 方法二:sh、bash脚本文件路径(这种方式可以不对脚本文件添加执行权限)

[root@c7-1 home]# ls -lh
-rw-r--r--.  1 root root  38 9月   2 18:56 test.s

[root@c7-1 home]# bash test.sh 
/boot
-rwxr-xr-x. 1 root root 5.7M 7月  22 01:24 vmlinuz-0-rescue-88592b0b2e2b49fab4e71eedc23b1998
-rwxr-xr-x. 1 root root 5.7M 8月  23 2017 vmlinuz-3.10.0-693.el7.x86_64

[root@c7-1 home]# sh test.sh 
/boot
-rwxr-xr-x. 1 root root 5.7M 7月  22 01:24 vmlinuz-0-rescue-88592b0b2e2b49fab4e71eedc23b1998
-rwxr-xr-x. 1 root root 5.7M 8月  23 2017 vmlinuz-3.10.0-693.el7.x86_64

3.3 方法三:source脚本文件路径(可以没有执行权限)

[root@c7-1 home]# source test.sh 
/boot
-rwxr-xr-x. 1 root root 5.7M 7月  22 01:24 vmlinuz-0-rescue-88592b0b2e2b49fab4e71eedc23b1998
-rwxr-xr-x. 1 root root 5.7M 8月  23 2017 vmlinuz-3.10.0-693.el7.x86_64

3.4 方法四:其他方法

[root@c7-1 /]# sh < /home/test.sh 
/boot
-rwxr-xr-x. 1 root root 5.7M 7月  22 01:24 vmlinuz-0-rescue-88592b0b2e2b49fab4e71eedc23b1998
-rwxr-xr-x. 1 root root 5.7M 8月  23 2017 vmlinuz-3.10.0-693.el7.x86_64

[root@c7-1 /]# cat /home/test.sh | sh
/boot
-rwxr-xr-x. 1 root root 5.7M 7月  22 01:24 vmlinuz-0-rescue-88592b0b2e2b49fab4e71eedc23b1998
-rwxr-xr-x. 1 root root 5.7M 8月  23 2017 vmlinuz-3.10.0-693.el7.x86_64

[root@c7-1 /]# cat /home/test.sh | bash
/boot
-rwxr-xr-x. 1 root root 5.7M 7月  22 01:24 vmlinuz-0-rescue-88592b0b2e2b49fab4e71eedc23b1998
-rwxr-xr-x. 1 root root 5.7M 8月  23 2017 vmlinuz-3.10.0-693.el7.x86_64

4.更完善的脚本构成

[root@c7-1 /]# vim /home/test.sh 

#!/bin/bash

#hellow
cd /boot

echo "当前目录位于:"
pwd

echo "其中以vml开头的文件包括:"
ls -lh vml*


[root@c7-1 /]# bash /home/test.sh 
当前目录位于:
/boot
其中以vml开头的文件包括:
-rwxr-xr-x. 1 root root 5.7M 7月  22 01:24 vmlinuz-0-rescue-88592b0b2e2b49fab4e71eedc23b1998
-rwxr-xr-x. 1 root root 5.7M 8月  23 2017 vmlinuz-3.10.0-693.el7.x86_64


三、重定向与管道操作

1.交互式硬件设备

类型设备文件文件描述编号默认设备
标准输入/dev/stdin0键盘
标准输出/dev/stdout1显示器
标准错误输出/dev/stderr2显示器

2.重定向操作

在这里插入图片描述

[root@c7-1 home]# vim passwd.txt 
12345
[root@c7-1 home]# passwd --stdin zhangsan < passwd.txt    //把passwd.txt的数据12345,重定向输入到passwd zhangsan用户下,即修改zhangsan密码为12345
更改用户 zhangsan 的密码 。
passwd:所有的身份验证令牌已经成功更新

[root@c7-1 home]# echo "123456" > passwd.txt  //重定向输出,将123456输入到passwd.txt
[root@c7-1 home]# cat passwd.txt 
123456

[root@c7-1 home]# cat passwd.txt 
12345
[root@c7-1 home]# echo "123456789" >> passwd.txt   //将123456789追加输出到passwd.txt尾部
[root@c7-1 home]# cat passwd.txt 
12345
123456789
[root@c7-1 home]# ls /tmp/ xxx 2>1.txt
[root@c7-1 home]# cat 1.txt 
ls: 无法访问xxx: 没有那个文件或目录

[root@c7-1 home]# ls /tmp/ www 2>>1.txt
[root@c7-1 home]# cat 1.txt 
ls: 无法访问xxx: 没有那个文件或目录
ls: 无法访问www: 没有那个文件或目录
#发现错误信息变成了两行
[root@c7-1 home]# ls /etc/passwd xxx &>> 1.txt
[root@c7-1 home]# cat 1.txt 
ls: 无法访问xxx: 没有那个文件或目录
/etc/passwd
&表示等同于的意思
1>&2 把标准输出重定向到标准错误
2>&1 把标准错误重定向到标准输出

[root@c7-1 home]# ls /etc/passwd xxx > 1.txt 2>&1
[root@c7-1 home]# cat 1.txt 
ls: 无法访问xxx: 没有那个文件或目录
/etc/passwd
#把标准输出 输出到1.txt 再把1.txt的标准错误重定向到标准输出

[root@c7-1 home]# ls /etc/passwd xxx 2> 1.txt 1>&2
[root@c7-1 home]# cat 1.txt 
ls: 无法访问xxx: 没有那个文件或目录
/etc/passwd
#把标准错误输出到1.txt 再把1.txt的标准输出重定向到标准错误

把它看作"黑洞",所有写入它的内容都会永远丢失.而尝试从它那儿读取内容则什么也读不到。然而 /dev/null 对命令行和脚本都非常的有用

[root@c7-1 home]# echo "123456" > /dev/null 
[root@c7-1 home]# cat /dev/null 
[root@c7-1 home]# 
#什么也看不到

3.管道操作符号 “ | ”

[root@c7-1 home]# grep "/bin/bash$" /etc/passwd | awk -F: '{print $1,$7}'
root /bin/bash
lz /bin/bash
zhangsan /bin/bash
#检索调用/bin/bash的第一行和第七行用户

[root@c7-1 home]# df -Th | grep "/$" | awk '{print $6}'
19%

重定向与管道操作是 shell环境中十分常用的功能,若能够熟练掌掘并灵活运用,将有助于编写代码简洁组功能强大的shell脚本程序


四、Shell的变量

1.变量的作用

2.变量的类型

五、自定义变量

1.变量的定义

Bash中的变量操作相对比较简单,不像其他高级编程语言(如C/C++、Java等)那么复杂。在定义一个新的变量时,一般不需要提前进行声明,而是直接指定变量名称并赋给初始值(内容)即可

2.定义一个新的变量

格式:
变量名=变量值
等号两边没有空格。变量名称需以字母或下划线开头,名称中不要包含特殊字符

2.1 取消变量

unset 变量名
[root@c7-1 home]# unset Pr

3.查看变量的值

通过在变量名称前添加前导符号"$",可以引用一个变量的值,使用echo 命令可以查看变量,可以在一条 echo命令中同时查看多个变量值

格式:
echo $变量名

[root@c7-1 home]# a=lz      //定义变量
[root@c7-1 home]# echo $a	//查看变量的值
lz
[root@c7-1 home]# b=666
[root@c7-1 home]# echo $a $b
lz 666


#当变量名称容易和紧跟其后的其他字符相混淆时,
#需要添加大括号“{}”将其括起来,否则将无法确定正确的变量名称。
#对于未定义的变量,将显示为空值
[root@c7-1 home]# echo $Pr
Python
[root@c7-1 home]# echo ${Pr}2.7.20
Python2.7.20

[root@c7-1 home]# echo ${test}RMB
RMB

4.echo选项

[root@c7-1 home]# echo -n hello   //-n表示不换行输出
hello[root@c7-1 home]#


[root@c7-1 home]# echo -e "hello\n"  //-e输出转义字符,转义后的内容将输出到屏幕上;\n 换行
hello								

[root@c7-1 home]# echo -e "hello\t"   // \t 转义后插入tab,即制表符
hello

#注:\转义符,跟在\之后的特殊符号将失去特殊含义,变为普通字符。
#如\$将输出"$"符号,而不当做是变量引用
	

5.特殊的赋值操作

1.双引号 " "

双引号允许通过$符号引用其他变量值,双引号主要起界定字符串的作用,特别是当要赋值的内容中包含空格时,必须以双引号括起来;其他情况下双引号通常可以省略

#当内容中有空格
[root@c7-1 home]# echo "hello world"
hello world

#当以变量的值进赋值
[root@c7-1 home]# version=2
[root@c7-1 home]# pyver="python $version"
[root@c7-1 home]# echo $pyver 
python 2

2.单引号 ’ ’

禁止引用其他变量值,$视为普通字符
但赋值内容中包含单引号 ‘’ 时,需使用’符号进行转义,以免冲突。

[root@c7-1 ~]# pyver='python $version'
[root@c7-1 ~]# echo $pyver 
python $version

3.反撇号 `

反撇号主要用于命令替换,允许将执行某个命令的屏幕输出结果赋值给变量。
反撇号括起来的范围内必须是能够执行的命令行,否则将会出错

[root@c7-1 ~]# ls -lh `which useradd`
-rwxr-x---. 1 root root 116K 11月  6 2016 /usr/sbin/useradd
#先通过 which useradd命令查找出 useradd 命令的程序位置,然后根据查找结果列出文件属性

[root@c7-1 ~]# time=`date +%T`
[root@c7-1 ~]# echo $time
13:56:41

#使用反撇号难以在一行命令中实现嵌套命令替换操作,
#这时可以改用 "$()" 来代替反撇号操作,以解决嵌套的问题
[root@c7-1 ~]# rpm -qc $(rpm -qf $(which useradd))
/etc/default/useradd
/etc/login.defs

4.read命令

除了上述赋值操作以外,还可以使用 Bash 的内置命令read来给变量赋值。
用来提示用户输入信息,从而实现简单的交互过程。执行时将从标准输入设备(键盘)读入
一行内容,并以空格为分隔符,将读入的各字段依次赋值给指定的变量(多余的内容赋值给
最后一个变量)。若指定的变量只有一个,则将整行内容赋值给此变量。

交互定义变量
-p 提示用户的信息
-n 定义字符数
-s 不显示用户输入的内容,常用于输入密码
-t 定义超时时间,超过多长时间没输出自动退出



[root@c7-1 ~]# read -p "请输入你的姓名:" name
请输入你的姓名:dashiji   
[root@c7-1 ~]# echo $name
dashiji

[root@c7-1 ~]# read -s -p "请输入你的密码:" pass
请输入你的密码:[root@c7-1 ~]# 
[root@c7-1 ~]# echo $pass
123

5.从文件读取内容赋值给变量

[root@c7-1 ~]# echo 192.168.3.3 > ip.txt
[root@c7-1 ~]# cat ip.txt 
192.168.3.3

[root@c7-1 ~]# read  -p "请输入你的IP:" IP < ip.txt
[root@c7-1 ~]# echo $IP
192.168.3.3

6. 设置变量的作用范围

默认情况下,新定义的变量只在当前的 Shell环境中有效,因此称为局部变量,当进入子程序或新的子Shell环境时,局部变量将无法再使用

#格式1:
export 变量名

#格式2:
export 变量名=变量值

#两种格式可以混合使用

为了使用户定义的变量在所有的子Shell环境中能够继续使用,减少重复设置工作,可以通过内部命令export
将指定的变量导出为全局变量。用户可以同时指定多个变量名称作为参数(无须使用"s"符号),变量名之间以空格分隔

[root@c7-1 ~]# name=zhangsan
[root@c7-1 ~]# test=18
[root@c7-1 ~]# echo $name $test
zhangsan 18
[root@c7-1 ~]# bash    //进入到子shell环境
[root@c7-1 ~]# echo $name $test 	
						//发现是空的
[root@c7-1 ~]# exit 
exit
[root@c7-1 ~]# export name test		//导出为全局变量
[root@c7-1 ~]# bash
[root@c7-1 ~]# echo $name $test		//子程序引用全局变量
zhangsan 18

使用export导出全局变量的同时,也可以为变量进行赋值,这样在新定义全局变量时就不需要提前进行赋值了,env查看用户当前环境变量

[root@c7-1 ~]# export abc=123
[root@c7-1 ~]# env
abc=123

7.变量运算

7.1 变量的运算

#格式:
expr 变量1 运算符 变量2 [运算符 变量3]...
加法运算:+
减法运算:-
乘法运算:\*
除法运算:/
求模(取余)运算:%

例:

[root@c7-1 ~]# expr 1+1
1+1
[root@c7-1 ~]# expr 1 + 1
2
[root@c7-1 ~]# expr 12 \* 2
24
[root@c7-1 ~]# expr 12 /  2
6

[root@c7-1 ~]# x=42
[root@c7-1 ~]# y=36
[root@c7-1 ~]# expr $x + 5
47
[root@c7-1 ~]# sum=`expr $y \* $y \* 2`
[root@c7-1 ~]# echo $sum
2592



[root@c7-1 ~]# vim shuzi.sh
#!/bin/bash
read -p "请输入第一个数字:" num1
read -p "请输入第二个数字:" num2

sum=`expr $num1 + $num2`

echo "求和数:$sum"

[root@c7-1 ~]# bash shuzi.sh 
请输入第一个数字:22
请输入第二个数字:22
求和数:44

[root@c7-1 ~]# echo $[10+10]
20

[root@c7-1 ~]# echo $((1+1))
2

六、特殊的Shell变量

1.环境变量

由系统提前创建,用来设置用户的工作环境
配置文件:/etc/profile、~/.bash_profile

使用env 命令可以查看到当前工作环境下的环境变量,对于常见的一些环境变量应了解其各自的用途。例如,变量USER表示用户名称,HOME表示用户的宿主目录,LANG表示语言和字符集,PWD表示当前所在的工作目录,
PATH 表示命令搜索路径等、RANDOM表示随机数,会返回0-32767的整数,USER表示当前账户的账户名称等,一般都用全大写定义,注意和自定义变量区分

[root@c7-1 ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin

[root@c7-1 ~]# echo $HOME
/root

[root@c7-1 ~]# echo $USER
root

[root@c7-1 ~]# echo $LANG
zh_CN.UTF-8

1.1 PATH变量

PATH变量用于设置可执行程序的默认搜索路径,当仅指定文件名称来执行命令程序时,Linux系统将在 PATIH变量指定的目录范围查找对应的可执行文件,如果找不到则会提示"command not found"。

[root@c7-1 ~]# fs.sh
bash: fs.sh: 未找到命令...

[root@c7-1 ~]# PATH="$PATH:/root"
[root@c7-1 ~]# fs.sh
123456

2.只读变量

[root@c7-1 ~]# name=11111
[root@c7-1 ~]# readonly name
[root@c7-1 ~]# echo $name 
11111
[root@c7-1 ~]# name=2222
-bash: name: 只读变量
[root@c7-1 ~]# unset name
-bash: unset: name: 无法反设定: 只读 variable
[root@c7-1 ~]# 

#重启则失效,可以修改

3.位置变量

[root@c7-1 ~]# vim user.sh
#!/bin/bash
useradd $1
echo $2 | passwd --stdin $1

[root@c7-1 ~]# bash user.sh lisi 123   //lisi为第一个位置参数,$1 ;123为第二个位置参数 $2
更改用户 lisi 的密码 。
passwd:所有的身份验证令牌已经成功更新

4.预定义变量

[root@c7-1 ~]# vim fuhao.sh
#!/bin.bash

echo $1
echo "$0 表示当前执行的脚本或程序的名称"
echo "$# 表示命令行中位置的参数个数"
echo "$* 所有位置参数的内容,这些内容是当做一个整体"
echo "$@ 表示列出所有未知参数,但是是以单个的形式列出

[root@c7-1 ~]# bash fuhao.sh 1 2 3 4
1
fuhao.sh 表示当前执行的脚本或程序的名称
4 表示命令行中位置的参数个数
1 2 3 4 所有位置参数的内容,这些内容是当做一个整体
1 2 3 4 表示列出所有未知参数,但是是以单个的形式列出


#理解 $* 和 $@ 的区别
$*  :把所有参数看成以空格分隔的一个字符串整体(单字符串)返回,代表"$1 $2 $3 $4"。
$@	:把各个参数加上双引号分隔成n份的参数列表,每个参数作为一个字符串返回,代表"$1" "$2" "$3" "$94"。

$*  :是将参数全部当做一个整体
$@	:是将参数每一个都当做单独的个体

set:查看系统所有的变量,包括环境变量和自定义变量(没有单独查看自定义变量的命令,可以set管道过滤)

总结

标签:Shell,变量,root,编程,echo,home,c7,bash
来源: https://blog.csdn.net/weixin_59410846/article/details/120061518