shell-笔记

一、shell基本知识

1.1Shell编程

shell程序的特点:
1、简单易学
2、解释性语言,不需要编译即可执行

1.2 什么是Shell

在学习Shell编程之前,必须弄清楚什么是Shell。为了能够使读者在学习具体的Shell编程之前对Shell有个基本的了解,本节将对Shell进行概括性的介绍,包括Shell的起源和功能。
1.2.1 shell的起源
1964年,美国AT&T公司的贝尔实验室、麻省理工学院及美国通用电气公司共同参与开始研发一套可以安装在大型主机上的多用户、多任务的操作系统,该操作系统的名称为Multics。1970年,丹尼斯•里奇和汤普逊启动了另外一个新的多用户、多任务的操作系统的项目,他们把这个项目称之为UNICS。1973年,使用C语言重新编写了Unix。通过这次编写,使得Unix得以移植到其他的小型机上面。1979年,第一个重要的标准UNIX Shell在Unix的第7版中推出,并以作者史蒂夫•伯恩(Stephen Bourne)的名字命名,叫做Bourne Shell,简称为sh。20世纪70年代末,C Shell作为2BSD UNIX的一部分发布,简称csh。之后又出现了许多其他的Shell程序,主要包括TenexCShell(tcsh)KornShell(ksh)以及GNU Bourne-Again shell(bash)。
1.2.2 shell的功能
Shell又称命令解释器,它能识别用户输入的各种命令,并传递给操作系统。它的作用类似于Windows操作系统中的命令行,但是,Shell的功能远比命令行强大的多。在UNIX或者localhost中,Shell既是用户交互的界面,也是控制系统的脚本语言。

1.3 shell的分类

Bourne Shell:标识为sh,该Shell由Steve Bourne在贝尔实验室时编写。在许多Unix系统中,该Shell是root用户的默认的Shell。
Bourne-Again Shell:标识为bash,该Shell由Brian Fox在1987年编写,是绝大多数localhost发行版的默认的Shell。Korn Shell:标识为ksh,该Shell由贝尔实验室的David Korn在二十世纪八十年代早期编写。它完全向上兼容 Bourne Shell 并包含了C Shell 的很多特性。C Shell:标识为csh,该Shell由Bill Joy在BSD系统上开发。由于其语法类似于C语言,因此称为C Shell。
如何查看当前系统支持的shell?

[root@localhost ~]# cat   /etc/shells
/bin/sh
/bin/bash
/sbin/nologin
/usr/bin/sh
/usr/bin/bash
/usr/sbin/nologin

如何查看当前系统默认shell?

[root@localhost ~]# echo $SHELL
/bin/bash

1.4 作为程序设计的语言——shell

Shell不仅仅是充当用户与UNIX或者localhost交互的角色,还可以作为一种程序设计语言来使用。通过Shell编程,可以实现许多非常实用的功能,提高系统管理的自动化水平。如果有一系列经常需要使用的命令,把它存储在一个文件里,shell可以读取这个文件并顺序执行其中的命令,我们把这样的文件就叫shell脚本。shell脚本按行解释文件里的命令。
对于一个基本的Shell程序来说,应该拥有以下基本元素:
1.声明:声明用哪个命令解释器来解释并执行当前脚本文件中的语句,一般写的解释器为:#!/bin/bash 。
2.命令:可执行语句,实现程序的功能。
3.注释:说明某些代码的功能,通过在代码中增加注释可以提高程序的可读性。
(1)单行注释:#开头的一整行都是注释,例如:
(2)多行注释,使用冒号“:”配合here document可实现多行注释,例如:
4.赋予rx的权限

1.5shell脚本编写规范

(1)脚本文件名应见名知意,例如backup_mysql.sh
(2)文件开头指定脚本解释器 #!/bin/sh 或 #!/bin/bash
(3)开头加版本特权等信息
(4)脚本中尽量不要用中文注释
别吝啬添加注释,必要的注释方便自己别人理解脚本逻辑和功能;
尽量用英文注释,防止本机或切换系统环境后中文乱码的困扰;
单行注释,可以放在代码行的尾部或代码行的上部;
多行注释,用于注解复杂的功能说明,可以放在程序体中,也可以放在代码块的开始部分。
(5)多使用内部命令
常用的内部命令有:echo、eval、exec、export、read、shift、exit
echo参数选项 说明
-n 不换行输出内容
-e 解析转义字符
echo可在屏幕上输出信息
#comment1
#comment2
#comment3
……
:<<BLOCK
……注释内容
BLOCK
Date:创建日期
Author:作者
Mail:联系方式
Function:功能
Version:版本
转义字符 说明
\n 换行
\r 回车
\t 制表符
\b 退格
\v 纵向制表符
示例:
eval
命令格式:eval args
功能:当shell程序执行到eval语句时,shell读入参数args,并将它们组合成一个新的命令,然后执行。
exec命令能够在不创建新的子进程的前提下,转去执行指定的命令,当指定的命令执行完毕后,该
进程就终止了。
export设置或者显示环境变量
read命令可从标准输入读取字符串等信息,传给shell程序内部定义的变量。
-p prompt:设置提示信息
-t timeout:设置输入等待时间,单位默认为秒

[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
[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

shift:在程序中每使用一次shift语句,都会使所有的位置参数依次向左移动一个位置,并使位置参数$#减1,直到减到0为止。
exit:退出shell程序。在exit之后可以有选择地指定一个数作为返回状态
仔细阅读出错信息
有时候我们修改了某个错误并再次运行后,系统依旧会报错。然后我们再次修改,但系统再次报错。这可能会持续很长时间。但实际上,旧的错误可能已经被纠正,只是由于出现了其它一些新错误才导致系统再次报错。

[root@localhost test]# read   -t 10 -p "please input your name:" name
please input your name:xiaoming
[root@localhost test]# echo $name
xiaoming

#读取两个输入(以空格隔开),分别赋值给name1和name2

[root@localhost test]# echo -n "please input your name:";read name1 name2 
please input your name:xiaoming xiaohong
[root@localhost test]# echo $name1
xiaoming
[root@localhost test]# echo $name2
xiaohong

[root@localhost ~]# vim ~/.vimrc

1.6shell脚本的执行方式

(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

1.7 执行脚本的方法

(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
[root@localhost test]# bash test2.sh
/tmp
[root@localhost test]# ./test2.sh
-bash: ./test2.sh: Permission denied
[root@localhost test]# chmod   a+rx   test2.sh
[root@localhost test]# ./test2.sh
/tmp
[root@localhost test]# source test2.sh
/tmp
[root@localhost tmp]# 
[root@localhost test]# . test2.sh
/tmp
[root@localhost 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`
[root@localhost test]# bash   test3.sh
[root@localhost test]# echo   $userdir
[root@localhost test]#
[root@localhost test]# chmod a+rx test3.sh
[root@localhost test]# ./test3.sh
[root@localhost test]# echo $userdir
[root@localhost test]#
[root@localhost test]# source test3.sh
[root@localhost test]# echo $userdir
/test
[root@localhost test]# . test3.sh
[root@localhost test]# echo $userdir
/test

1.10 shell脚本的退出状态

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

二、变量和引用

2.1 什么是变量

顾名思义,变量就是程序设计语言中的一个可以变化的量,当然,可以变化的是变量的值。几乎所有的程序设计语言中都有定义变量,并且其涵义也大同小异。从本质上讲,变量就是在程序中保存用户数据的一块内存空间,而变量名就是这块内存空间的地址。在程序的执行过程中,保存数据的内存空间的内容可能会不断地发生变化,但是,代表内存地址的变量名却保持不变。

2.2变量的命名

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

2.3 变量的类型

2.3.1 根据数据类型分类
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将变量变成非环境变量

2.3.2 根据作用域分类
根据作用域可将变量分为环境变量(全局变量)和普通变量(局部变量)
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

2.4 变量的定义

在Shell中,通常情况下用户可以直接使用变量,而毋需先进行定义,当用户第一次使用某个变量名时,实际上就同时定义了这个变量,在变量的作用域内,用户都可以使用该变量。
1、变量定义示例:变量名=变量值
注意:
(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脚本会根据参数的位置使用不同的位置参数变量读取它们的值。
在这里插入图片描述
示例

[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

2.5 shell中的引用
在bash中有很多特殊字符,这些特殊字符就具有特殊含义。引用就是通知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`

2.6变量的运算

在这里插入图片描述

在这里插入图片描述

示例:

  • [ ]
[root@localhost ~]# r=$((2+5*8)) 
[root@localhost ~]# echo $r 42
[root@localhost ~]# let r=3+2 
[root@localhost ~]# echo $r 5
[root@localhost ~]# r=`expr 4+2` 
[root@localhost ~]# echo $r 4+2
[root@localhost ~]# r=`expr 4 + 2` 
[root@localhost ~]# echo $r 6

#使用expr计算字符的长度

[root@localhost test4]# char="i have a"
[root@localhost test4]# expr length "$char"
8
[root@localhost ~]# r=$[3+2]
[root@localhost ~]# echo $r
5
[root@localhost ~]# awk 'BEGIN {print 2+3*2}'
8
[root@localhost test4]# echo "6.282 3.14" | awk '{print ($1-$2)}'
3.142
[root@localhost ~]# declare -i r=3+2
[root@localhost ~]# echo $r
5

实验:计算用户输入的任意两个整数的和、差、乘积、商、余数。
方法一:

[root@localhost test4]# cat 1.sh 
#!/bin/bash
a=$1
b=$2
echo a+b=$(($a+$b))
echo a-b=$((a-b))
echo a*b=$((a*b))
echo a/b=$((a/b))
echo a%b=$((a%b))
[root@localhost test4]# ./1.sh 10 3
a+b=13
a-b=7
a*b=30
a/b=3
a%b=1

方法二:

[root@localhost test4]# cat 1.1.sh 
#!/bin/bash
read -p "please input two number:" a b
echo $a+$b=$(($a+$b))
echo $a-$b=$((a-b))
echo $a*$b=$((a*b))
echo $a/$b=$((a/b))
echo $a%$b=$((a%b))
[root@localhost test4]# ./1.1.sh 
please input two number:3 4
3+4=7
3-4=-1
3*4=12
3/4=0
3%4=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
#输出右边的几个字符
[root@localhost ~]# echo ${str1:0-5}
world
[root@localhost ~]# echo ${str1: -5}
world
#提取完整字符串
[root@localhost ~]# echo ${str1:-5}
hello world

示例:删除字符串

#获取后缀名.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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值