Linux——shell脚本笔记01

文章目录

    • 第一章
    • 1. shell脚本的基本元素
    • 2. shell脚本编写规范
    • 3.shell脚本的执行方式
    • 4.执行脚本的方法
    • 5. shell脚本的退出状态
    • 第二章
    • 1.变量的命名
    • 2. 变量的类型
    • 3.变量的定义
    • 4.shell中的引用
    • 5.变量的运算

第一章

1. shell脚本的基本元素

对于一个基本的Shell程序来说,应该拥有以下基本元素:
[root@localhost ~]# cat /etc/shells
/bin/sh
/bin/bash
/sbin/nologin
/usr/bin/sh
/usr/bin/bash
/usr/sbin/nologin
[root@localhost ~]# echo $SHELL
/bin/bash
1.声明:声明用哪个命令解释器来解释并执行当前脚本文件中的语句,一般写的解释器为
#!/bin/bash 。
2.命令:可执行语句,实现程序的功能。
3.注释:说明某些代码的功能,通过在代码中增加注释可以提高程序的可读性。
(1)单行注释:#开头的一整行都是注释,例如:

#comment1
#comment2
#comment3
……

(2)多行注释,使用冒号“:”配合here document可实现多行注释,例如:

:<<BLOCK
……注释内容
BLOCK

4.赋予rx的权限

2. shell脚本编写规范

(1)脚本文件名应见名知意,例如backup_mysql.sh
(2)文件开头指定脚本解释器 #!/bin/sh 或 #!/bin/bash
(3)开头加版本特权等信息

# Date:创建日期
# Author:作者
# Mail:联系方式
# Function:功能
# Version:版本

(4)脚本中尽量不要用中文注释
别吝啬添加注释,必要的注释方便自己别人理解脚本逻辑和功能;
尽量用英文注释,防止本机或切换系统环境后中文乱码的困扰;
单行注释,可以放在代码行的尾部或代码行的上部;
多行注释,用于注解复杂的功能说明,可以放在程序体中,也可以放在代码块的开始部分。
(5)多使用内部命令
常用的内部命令有:echo、eval、exec、export、read、shift、exit
echo参数选项
-n 不换行输出内容
-e 解析转义字符
\n 换行
\r 回车
\t 制表符
\b 退格
\v 纵向制表符
例如:

[root@localhost ~]# echo -n i have a cat
i have a cat[root@localhost ~]#
[root@localhost ~]# echo i\thave\ta\tcat
ithavetatcat
[root@localhost ~]# echo -e i\thave\ta\tcat
ithavetatcat
[root@localhost ~]# echo -e "i\thave\ta\tcat"
i have a cat

eval
命令格式:eval args
功能:当shell程序执行到eval语句时,shell读入参数args,并将它们组合成一个新的命令,然后执
行。
例如:

[root@localhost test]# a='shuju;head -1 /etc/passwd'
[root@localhost test]# echo $a
shuju;head -1 /etc/passwd
[root@localhost test]# eval echo $a
shuju
root:x:0:0:root:/root:/bin/bash

exec命令能够在不创建新的子进程的前提下,转去执行指定的命令,当指定的命令执行完毕后,该
进程就终止了。
export设置或者显示环境变量
read命令可从标准输入读取字符串等信息,传给shell程序内部定义的变量。
-p prompt:设置提示信息
-t timeout:设置输入等待时间,单位默认为秒
例如:

[root@localhost test]# read -t 10 -p "please input your name:" name
please input your name:xiaoming
[root@localhost test]# echo $name
xiaoming
[root@localhost test]# echo -n "please input your name:";read name1 name2
#读取两个输入(以空格隔开),分别赋值给name1和name2
please input your name:xiaoming xiaohong
[root@localhost test]# echo $name1
xiaoming
[root@localhost test]# echo $name2
xiaohong

shift,在程序中每使用一次shift语句,都会使所有的位置参数依次向左移动一个位置,并使位置参
数$#减1,直到减到0为止。
exit,退出shell程序。在exit之后可以有选择地指定一个数作为返回状态
(6)没有必要使用cat命令

eg:cat /etc/passwd | grep guru
使用以下方式即可
eg:grep guru etc/passwd

(7)代码缩进
示例:

#!/bin/bash
i=1
while [ $i -le 10 ]
do
if [ $i -le 9 ]
then
username=user0$i
else
username=user$i
fi
! id $username &>/dev/null && {
useradd $username
echo $username | passwd --stdin $username &>/dev/null
}
let i++
done

(8)仔细阅读出错信息
有时候我们修改了某个错误并再次运行后,系统依旧会报错。然后我们再次修改,但系统再次报
错。这可能会持续很长时间。但实际上,旧的错误可能已经被纠正,只是由于出现了其它一些新错误才
导致系统再次报错。
如何快速如何快速生成脚本开头的版本版权注释信息

[root@localhost ~]# vim ~/.vimrc
autocmd BufNewFile *.py,*.cc,*.sh,*.java exec ":call SetTitle()"
func SetTitle()
if expand("%:e") == 'sh'
call setline(1,"#!/bin/bash")
call setline(2,"#########################")
call setline(3,"#File name:".expand("%"))
call setline(4,"#Version:v1.0")
call setline(5,"#Email:[email protected]")
call setline(6,"#Created time:".strftime("%F %T"))
call setline(7,"#Description:")
call setline(8,"#########################")
call setline(9,"")
endif
endfunc

3.shell脚本的执行方式

(1)交互式执行

[root@localhost ~]# for filename in `ls /etc`
> do
> if echo "$filename" | grep "passwd"
> then
> echo "$filename"
> fi
> done

(2)作为程序文件执行(常用)
对于一组需要经常重复执行的Shell语句来说,将它们保存在一个文件中来执行。我们通常称这种包
含多个Shell语句的文件为Shell脚本,或者Shell脚本文件。脚本文件是普通的文本文件,可使用任何的
文本编辑器查看或修改Shell脚本。

[root@localhost ~]# mkdir /test
[root@localhost ~]# cd /test
[root@localhost test]# vim test1.sh
#!/bin/bash
for filename in `ls /etc`
do
if echo "$filename" | grep "passwd"
then
echo "$filename"
fi
done

4.执行脚本的方法

(1)bash ./filename.sh(产生子进程,再运行,使用当前指定的bash shell去运行)
(2)./filename.sh(产生子进程,再运行,使用脚本里面指定的shell去运行。使用该种方式执行需要x
权限)
(3)source ./filename.sh(source命令是一个shell内部命令,其功能是读取指定的shell程序文件,并
且依次执行其中的所有的语句,并没有创建新的子shell进程,所以脚本里面所有创建的变量都会保存到
当前的shell里面)
(4). filename.sh(和source一样,也是使用当前进程执行)
示例一:

[root@localhost test]# vim test2.sh
#!/bin/bash
cd /tmp
pwd
[root@localhost test]# ls -l test2.sh
-rw-r--r--. 1 root root 24 Apr 30 20:09 test2.sh
(1)[root@localhost test]# bash test2.sh
/tmp
(2)[root@localhost test]# ./test2.sh
-bash: ./test2.sh: Permission denied
[root@localhost test]# chmod a+rx test2.sh
[root@localhost test]# ./test2.sh
/tmp
(3)[root@localhost test]# source test2.sh
/tmp
[root@localhost tmp]#
(4)[root@localhost test]# . test2.sh
/tmp

执行shell脚本时,如果使用1和2这种方式执行会在当前的进程下产生一个新的bash子进程,所以子进程
切换到了/tmp目录,当脚本结束,子进程也就结束了,所以当前进程的目录不会发生变化;3和4方式执
行时,不会产生新的进程,所以脚本执行结束后当前的目录会变成/tmp。
示例二:

[root@localhost test]# echo 'userdir=`pwd`' > test3.sh
[root@localhost test]# cat test3.sh
userdir=`pwd`
(1)[root@localhost test]# bash test3.sh
[root@localhost test]# echo $userdir
[root@localhost test]#
(2)[root@localhost test]# chmod a+rx test3.sh
[root@localhost test]# ./test3.sh
[root@localhost test]# echo $userdir
[root@localhost test]#
(3)[root@localhost test]# source test3.sh
[root@localhost test]# echo $userdir
/test
(4)[root@localhost test]# . test3.sh
[root@localhost test]# echo $userdir

5. shell脚本的退出状态

在UNIX或者Linux中,每个命令都会返回一个退出状态码。退出状态码是一个整数,其有效范围为
0~255。通常情况下,成功的命令返回0,而不成功的命令返回非0值。非0值通常都被解释成一个错误
码。行为良好的UNIX命令,程序和工具都会返回0作为退出码来表示成功。
Shell脚本中的函数和脚本本身也会返回退出状态码。在脚本或者是脚本函数中执行的最后的命令会决定
退出状态码。另外,用户也可以在脚本中使用exit语句将指定的退出状态码传递给Shell。

第二章

1.变量的命名

在Shell中,变量名可以由字母、数字或者下划线组成,并且只能以字母或者下划线开头。对于变量
名的长度,Shell并没有做出明确的规定。因此,用户可以使用任意长度的字符串来作为变量名。但是,
为了提高程序的可读性,建议用户使用相对较短的字符串作为变量名。
在一个设计良好的程序中,变量的命名有着非常大的学问。通常情况下,用户应该尽可能选择有明
确意义的英文单词作为变量名,尽量避免使用拼音或者毫无意义的字符串作为变量名。这样的话,用户
通过变量名就可以了解该变量的作用。

2. 变量的类型

根据数据类型分类
Shell是一种动态类型语言和弱类型语言,即在Shell中,变量的数据类型毋需显示地声明,变量的
数据类型会根据不同的操作有所变化。准确地讲,Shell中的变量是不分数据类型的,统一地按照字符串
存储。但是根据变量的上下文环境,允许程序执行一些不同的操作,例如字符串的比较和整数的加减等
等。
什么是弱类型语言、强类型语言?
强类型和弱类型主要是站在变量类型处理的角度进行分类的。强类型是指不允许隐式变量类型转换,弱
类型则允许隐式类型转换。
强类型语言,当你定义一个变量是某个类型,如果不经过代码显式转换(强制转化)过,它就永远
都是这个类型,如果把它当做其他类型来用,就会报错
弱类型语言,你想把这个变量当做什么类型来用,就当做什么类型来用,语言的解析器会自动(隐
式)转换。
比如:
C语言定义变量,int+变量名,实则前面的int就是给变量内存划分了等级,int定义整型所以空间里
只能存放整型,这就是强类型。php、C#和Python等都是强类型语言。
可以使用declare定义变量的类型:declare attribute variable
注:declare命令还可输出所有的变量、函数、整数和已经导出的变量
-p:显示所有变量的值
-i:将变量定义为整数,在之后就可以直接对表达式求值,结果只能是整数。如果求值失败或者不是整
数,就设置为0。
-r:将变量声明为只读变量。只读变量不允许修改,也不允许删除。(也可使用readonly定义只读变量)
-a:变量声明为数组变量。但这没有必要,所有变量都不必显示定义就可以用作数组。事实上,在某
种意义上,似乎所有变量都是数组,而且赋值给没有下标的变量与赋值给下标为0的数组元素相同。
-f:显示所有自定义函数,包括名称和函数体。
-x:将变量设置成环境变量。可使用+x将变量变成非环境变量
根据作用域分类
根据作用域可将变量分为环境变量(全局变量)和普通变量(局部变量)
1、环境变量
环境变量也可称为全局变量,可以在创建它们的shell及其派生出来的任意子进程shell中使用(su -
切换用户会读取新的环境变量),环境变量又可分为自定义环境变量和bash内置的环境变量。
(1)自定义环境变量
一般是指用export内置命令导出的变量,用于定义shell的运行环境境,保证shell命令的正确执行。环
境变量可以在命令行中设置和创建,但用户退出命令行时这些变量值就会丢失,即该环境变量只在当前
shell和子shell中有效。如果希望永久保存环境变量,可以在配置文件中设置。
①用户的环境变量配置(non-login shell)
/.bash_profile或/.bashrc
②全局环境变量的配置(login shell)
/etc/bashrc、/etc/profile文件或者/etc/profile.d目录中定义。
注意:按照系统规范,所有环境变量的名字均采用大写形式。在将环境变量应用于用户进程程序之前,
都应该用命令export导出。
有一些环境变量,比如HOME,PATH,SHELL,UID,USER等,在用户登录前就已经被/bin/login程序设置
好了,通常环境变量被定义并保存在用户家目录下的.bash_profile文件或全局的配置文件/etc/profile
中。
(2)bash内置的环境变量
shell内置的环境变量是所有的shell程序都可以使用的变量。shell程序在运行时,都会接收一组变量
来确定登录用户名、命令路径、终端类型、登录目录等,这组变量就是环境变量。环境变量会影响到所
有的脚本的执行结果。
变量
PATH 命令搜索路径,以冒号为分隔符
HOME 用户主目录的路径名,是cd命令的默认参数
COLUMNS 定义了命令编辑模式下可使用命令行的长度
HISTFILE 命令历史文件
HISTSIZE 命令历史文件中最多可包含的命令条数
HISTFILESIZE 命令历史文件中包含的最大行数
IFS 定义shell使用的分隔符
LOGNAME 当前的登录名
SHELL shell的全路径名
TERM 终端类型
TMOUT shell自动退出的时间,单位为秒,若设为0则禁止shell自动退出
PWD 当前工作目录
注:可使用env查看环境变量
(2)普通变量也可称为局部变量,与全局变量相比,局部变量的使用范围较小,通常仅限于某个程序段
访问,例如函数内部。在Shell语言中,可以在函数内部通过local关键字定义局部变量,另外,函数的参
数也是局部变量。
示例:全局变量和局部变量的区别

[root@localhost ~]# vim 6.sh
#!/bin/bash
#定义函数
func()
{
#输出全局变量v1的值
echo "global variable v1 is $v1"
#定义局部变量v1
local v1=2
#输出局部变量v1的值
echo "local variable v1 is $v1"
}
#定义全局变量v1
v1=1
#调用函数
func
#输出全局变量v1的值
echo "global variable v1 is $v1"
[root@localhost test]# chmod a+rx var.sh
[root@localhost test]# ./var.sh
global variable v1 is 1
local variable v1 is 2
global variable v1 is 1

3.变量的定义

在Shell中,通常情况下用户可以直接使用变量,而毋需先进行定义,当用户第一次使用某个变量名
时,实际上就同时定义了这个变量,在变量的作用域内,用户都可以使用该变量。
1、变量定义示例:变量名=变量值

#!/bin/bash
#定义变量a
a=1
#定义变量b
b="hello"
#定义变量c
c="hello world"
#定义备份路径
bak_dir=/data/backup
#把一个命令的结果赋值变量
变量名=`ls`
变量名=$(ls)

注意:
(1)“=”前后不能有空格

[root@localhost ~]# a= 3
-bash: 3: 未找到命令
[root@localhost ~]# b =4
-bash: b: 未找到命令

(2)字符串类型建议用引号括起来,尤其是特殊字符或有空格

stu_name="zhang san"

引用变量: 变量名或者 变量名 或者 变量名或者{变量名}
查看变量:echo $变量名,set(可查看所有变量:包括自定义变量和环境变量),env显示全局变量,
declare输出所有的变量、函数、整数和已经导出的变量。
取消变量:unset 变量名
作用范围:仅在当前shell中有效
注:可使用export指令将变量转换成环境变量
2、位置参数和预定义变量
许多情况下,Shell脚本都需要接收用户的输入,根据用户输入的参数来执行不同的操作。
从命令行传递给Shell脚本的参数又称为位置参数,Shell脚本会根据参数的位置使用不同的位置参数变量
读取它们的值。
变量
$# 命令行参数的个数
$n 表示传递给脚本的第n个参数,例如$1表示第一个参数,$2表示第二个参数,$3表示第三
个参数
$0 当前脚本的名称
$* 以"参数1 参数2 参数3…"的形式返回所有参数的值
$@ 以“参数1”“参数2”“参数3”…的形式返回所有的值
? 前一个命令或者函数的返回状态码。 ? 前一个命令或者函数的返回状态码。 ?前一个命令或者函数的返回状态码。?的返回值用法:(1)判断命令、脚本或函数等程序
是否执行成功(2)若在脚本中调用执行“exit 数字”,则会返回这个数字给“ ? ”变量( 3 )如果是在函数里,则通过“ r e t u r n 数字”把这个数字以函数值的形式传给“ ?”变量(3)如 果是在函数里,则通过“return 数字”把这个数字以函数值的形式传给“ ?变量(3)如果是在函数里,则通过return数字把这个数字以函数值的形式传给?”
$$ 返回本程序的进程ID(PID),不常用
$! 获取上一个在后台工作的进程的进程号,不常用
$_ 保存之前执行的命令的最后一个参数,不常用
示例:

[root@localhost test]# vim param.sh
echo "第1个位置参数是$1"
echo "第2个位置参数是$2"
echo "所有参数是: $*"
echo "所有参数是: $@"
echo "参数的个数是: $#"
echo "当前进程的PID是: $$"
[root@localhost test]# bash param.sh shuju1 shuju2
第1个位置参数是shuju1
第2个位置参数是shuju2
所有参数是: shuju1 shuju2
所有参数是: shuju1 shuju2
参数的个数是: 2
当前进程的PID是: 23278

$?的示例:

[root@localhost test]# vim ping.sh
#!/bin/bash
ping -c2 $1 &> /dev/null
if [ $? = 0 ];then
echo "host $1 is ok"
else
echo "host $1 is fail"
fi
[root@localhost test]# chmod a+rx ping.sh
[root@localhost test]# ./ping.sh 192.168.168.128
host 192.168.168.128 is ok

∗ 和 *和 @的区别示例:

[root@localhost test]# set -- "i have" a cat #利用set命令设置位置参数
[root@localhost test]# echo $#
3
[root@localhost test]# echo $*
i have a cat
[root@localhost test]# echo $@
i have a cat
[root@localhost test]# for i in $*;do echo $i;done
i
have
a
cat
[root@localhost test]# for i in $@;do echo $i; done
i
have
a
cat
[root@localhost test]# for i in "$*";do echo $i;done
i have a cat
[root@localhost test]# for i in "$@";do echo $i;done
i have
a
cat
[root@localhost test]# shift #使用该指令可将位置参数左移一位
[root@localhost test]# echo $1
a
[root@localhost test]# shift
[root@localhost test]# echo $1
cat

4.shell中的引用

在bash中有很多特殊字符,这些特殊字符就具有特殊含义。引用就是通知shell将这些特殊字符当作普通
字符来处理。
符号说明:
转义字符“\”
如果将\放到特殊字符前面,shell就忽略这些特殊字符的原有含义,把它们当作普通字符对待
单引号
如果将字符串放到一对单引号之间,那么字符串中所有字符的特殊含义被忽略
双引号
双引号的引用与单引号基本相同,包含在双引号内的大部分特殊字符可以当作普通字符处
理,但是仍然有一些特殊字符保留自己的特殊含义,比如”$“和“\”以及“ ` ”
说明:反引号中的字符串将被解释为shell命令

[root@localhost ~]# echo "current_user is: $USER"
current_user is: root
[root@localhost ~]# echo 'current_user is: $USER'
current_user is: $USER
[root@localhost ~]# echo "current_user is: `whoami`"
current_user is: root
[root@localhost ~]# echo 'current_user is: `whoami`'
current_user is: `whoami`

5.变量的运算

Linux——shell脚本笔记01_第1张图片
Linux——shell脚本笔记01_第2张图片
Linux——shell脚本笔记01_第3张图片

示例:截取字符串
[root@localhost ~]# str1="hello world"
#返回变量长度
[root@localhost ~]# echo ${#str1}
11
#变量截取
#指定起始位置,一直到结束
[root@localhost ~]# echo ${str1:1}
ello world
#指定长度,不指定起始位置默认从开头开始
[root@localhost ~]# echo ${str1::3}
hel
#指定起始位置和长度
[root@localhost ~]# echo ${str1:1:3}
ell
#从右边第几个字符开始,及字符的个数
[root@localhost ~]# echo ${str1:0-1:1}
 d
示例:删除字符串
#获取后缀名tar.gz
[root@localhost ~]# filename=testfile.tar.gz
[root@localhost ~]# file=${filename#*.}
[root@localhost ~]# echo $file
tar.gz
#获取后缀名.gz
[root@localhost ~]# filename=testfile.tar.gz
[root@localhost ~]# file=${filename##*.}
[root@localhost ~]# echo $file
gz
#截取testfile.tar
[root@localhost ~]# filename=testfile.tar.gz
[root@localhost ~]# file=${filename%.*}
[root@localhost ~]# echo $file
testfile.tar
#截取testfile
[root@localhost ~]# filename=testfile.tar.gz
[root@localhost ~]# file=${filename%%.*}
[root@localhost ~]# echo $file
testfile

你可能感兴趣的:(SHELL,笔记,linux,bash,运维)