shell学习笔记

一、shell概述

  • shell 的两层含义: 既是一种应用程序,又是一种程序设计语言

1.1 shell作为应用程序

  • 解释、执行 用户输入的 命令,将用户的操作翻译成机器可以识别的语言,完成相应功能称之为 shell 命令解析器
  • shell 是用户和 Linux 内核之间的接口程序,提供了用户操作内核的工具,shell包含多个接口,对应 用户终端输入的命令,当我们向终端输入指令时,一回车就会启动一个shell,shell把回车的那个字符串拿来运行,启动某个应用程序,这个应用程序去和内核产生一些结果。
  • shell调用了系统核心的大部分功能来执行程序、并以 并行 的方式协调各个程序的运行,一个shell对应一个终端
  • Linux 系统中提供了好几种不同的 shell 命令解释器,如 sh、ash、bash 等。一般默认使用 bash 作为默认的解释器。

在这里插入图片描述

shell本质是对内核起到保护作用,只有shell能够识别的命令才能够直接操作内核来控制硬件

1.2 shell作为一门语言

  • shell定义了各种变量和参数,并提供了许多在高级语言中才具有的控制结构,包括循环和分支,用于简化我们对系统的管理与应用程序的部署称之为shell脚本

编译性语言和脚本语言的区别:

  • 我们学过的 c/c++等语言,属于编译性语言(需经过编译器完成编译、汇编、链接等过程变为二进制代码方可执行)
  • shell脚本是一种脚本语言,我们只需使用任意文本编辑器,按照语法编写相应程序,增加可执行权限,即可在安装了 shell 命令解释器的环境下执行

shell 脚本主要用于:

  • 帮助开发人员或系统管理员将复杂而又反复的操作放在一个文件中,通过简单的 一步执行 操作完成相应任务,从而解放他们的负担

shell 脚本大体可以分为两类:
(1)系统进行调用
这类脚本无需用户调用,系统会在合适的时候调用,如:/etc/profile、~/.bashrc 等

  • /etc/profile 此文件为系统的 每个用户 设置环境信息,当用户第一次登录时,该文件被执行,系统的公共环境变量在这里
    设置开始自启动的程序,一般也在这里设置
  • ~/.bashrc 登录时会自动调用,打开任意终端时也会自动调用
    这个文件一般设置与个人用户有关的环境变量,如交叉编译器的路径等等

(2)用户编写,需要手动调用的

无论是系统调用的还是需要我们自己调用的,其语法规则都一样

二、shell 脚本的定义与执行

2.1shell语法

  • 1、定义以开头:#!/bin/bash
    #!用来声明脚本由什么 shell 解释,否则使用默认 shell
  • 2、单个"#"号代表注释当前行
  • 3、执行: chmod + x test.sh ./test.sh 增加可执行权限后执行 bash test.sh 直接指定使用 bash
    解释 test.sh . test.sh(source test.sh) 使用当前 shell 读取解释 test.sh

2.2shell脚本的代码编写流程
第一步:指定shell脚本文件,一般以.sh作为后缀名,也可以不加,因为Linux不以后缀作为文件区分,例如:test.sh
第二步:编写代码

#!/bin/bash
# #!用于指定当前脚本文件的shell解释器的类型,如果不写,则用默认的shel
# shell脚本是shell命令的有序集合,代码的构成就是命令
ls

pwd

echo "study~"

第三步:修改文件权限

chmod +x test.sh

第四步:执行脚本文件

./test.sh 
或者 bash test.sh 
或者 . test.sh(后两种方式不需要修改文件权限)

执行结果:
在这里插入图片描述
三种执行脚本的方式不同点:

  1. ./和 bash 执行过程基本一致,前者首先检测#!,使用#!指定的 shell,如果没有则使用默认的 shell,后者明确指定
    bash 解释器去执行脚本,脚本中#!指定的解释器不起作用
  2. 用./和 bash 去执行会在后台启动一个新的 shell 去执行脚本 用.去执行脚本不会启动新的 shell,直接由当前的 shell
    去解释执行脚本。

2.2 变量
2.2.1 自定义变量

  • 定义变量 变量名=变量值 如:num=10
  • 引用变量 $ + 变量名 如:i=$num 把变量 num 的值付给变量 i
  • 显示变量 使用 echo 命令可以显示 单个 变量取值 echo $num
  • 清除变量 使用 unset 命令清除变量 unset num

变量的其它用法:

  • read string 从键盘输入一个字符串付给变量 string
  • readonly var=100 定义一个只读变量,只能在定义时初始化,以后不能改变,不能被清除。
  • export var=300 使用 export 说明的变量,会被导出为环境变量,其它 shell 均可使用 注意:此时必须使用source 2_var.sh 才可以生效

注意事项:

  1. 变量名只能包含英文字母下划线,不能以数字开头
    1_num=10 错误
    num_1=20 正确
  2. 等号两边不能直接接空格符,若变量中本身就包含了空格,则整个字符串都要用双引号、或单引号括起来;
    name=aa bb //错误
    name=“aa bb” //正确
  3. 双引号内的特殊字符可以保有变量特性,但是单引号内的特殊字符则仅为一般字符。
    echo “$name is me” //输出:aa bb
    is me echo ’ $name is me’ //输出: $name is me

代码示例:

#!/bin/bash

#定义变量
#shell脚本中没有数据类型可言,所以定义变量时不需要加数据类型
#shell脚本中,赋值操作时不能在等号两边加空格
#NUM = 100 #错误
NUM=100

#引用变量
# $变量名 取一个变量的值
i=$NUM

#显示变量
echo $NUM
echo $i

#清除变量
unset NUM
echo "*************"
echo $NUM

#使用read从终端读取数据保存在变量中
read str
echo "str = $str"

#使用readonly创建一个只读的变量
readonly n=999
echo "n = $n"

#指定变量初始化后不能再次修改变量的值,只能使用
#n=666
#echo "n = $n"

执行结果:
在这里插入图片描述
2.2.2 环境变量

  • shell 在开始执行时就已经定义了一些和系统的工作环境有关的变量,我们在 shell 中可以直接使用$name 引用

定义:

  • 一般在~/.bashrc 或/etc/profile 文件中(系统自动调用的脚本)使用 export 设置,允许用户后来更改
    VARNAME=value
    export VARNAME
    传统上,所有环境变量均为大写
    显示环境变量
    使用 env 命令可以查看所有的环境变量。
    清除环境变量
    使用 unset 命令清除环境变量

常见环境变量:

  • HOME:用于保存注册目录的完全路径名。

  • PATH:用于保存用冒号分隔的目录路径名,shell 将按 PATH变量中给出的顺序搜索这些目录,找到的第一个与命 令名称一致的可执行文件将被执行。
    PATH=$HOME/bin:/bin:/usr/bin;export PATH

  • HOSTNAME:主机名

  • SHELL:默认的shell 命令解析器

  • LOGNAME:此变量保存登录名

  • PWD:当前工作目录的绝对路径名

设置环境变量:
方法1:临时设置
在终端执行命令

MYVAL=999  
export MYVAL

方法2:永久设置
需要在配置文件(~/.bashrc或/etc/profile)中进行设置,设置完毕后需要通过 source命令配置文件立即生效

代码示例:使用环境变量,一般环境变量类似c语言中的全局变量,可以再shell脚本文件中任意使用

#!/bin/bash

echo "You are welcome to use bash"
echo "Current work dirctory is $PWD"
echo "the host name is  $HOSTNAME"
echo "your home dir  $HOME"
echo "Your shell is  $SHELL"
echo "user env val is $MYVAL1"

执行结果:
在这里插入图片描述
2.2.3 预设变量

在这里插入图片描述
代码示例:

#! /bin/bash

#位置变量$0 - $9 保存从终端输入的每一个参数
#\用于转义$
echo "\$0 = $0"
echo "\$1 = $1"
echo "\$2 = $2"
echo "\$5 = $5"
echo "\$6 = $6"
echo "\$7 = $7"
echo "\$8 = $8"
echo "\$9 = $9"
#如果超过9,需要加大括号
echo "\$10 = ${10}"

#$#:保存命令行传入的参数的个数,不包括$0
echo "\$# = $#"

#$@或者$*:保存所有的命令行传入的参数,但是不包括$0
echo "\$@ = $@"
echo "\$* = $*"

#$$:获取当前进程的进程号
echo "\$$ = $$"
//read NUM

# $?返回上一个命令执行的结果,如果执行成功,则$?的值为0,执行失败,则为非0
ls
echo "\$? = $?"

ls asdfasdf
echo "\$? = $?"

执行结果:
在这里插入图片描述
2.2.4 脚本变量的特殊用法

  1. “”(双引号):包含的变量会被解释

  2. ‘’(单引号):包含的变量会被当做字符串解释

  3. ``(数字键1左面的反引号):反引号中的内容作为系统命令,并执行其内容,可以替换输出为 一个变量
    例如:$ echo "today isdate "
    输出结果:today is 2012年07月29日星期日 12:55:21 CST

  4. \ 转义字符: 同c语言 \n \t \r \a等 echo命令需加-e转义

  5. ( 命令序列 ): 由子shell来完成,不影响当前shell中的变量
    { 命令序列 }: 在当前shell中执行,会影响当前变量
    注意: “{”、“}”前后有一空格

代码示例:

#!/bin/bash

name="zhangsan"
#双引号里面的特殊字符,会使用其特殊含义
string1="good moring $name"
#单引号里面的特殊字符,都会失去特殊含义
string2='good moring $name'

echo $string1
echo $string2

#反引号:获取一个shell命令的输出结果,一般对有输出结果的命令经常去使用,也可以使用$()与反引号等价
echo "today is date"
echo "today is `date`"
echo 'today is `date`'
echo "My dir is $(ls)"

#转义字符:使用时,需要在echo后面加上-e选项
echo "**************"
echo "this \n is\ta\ntest"
echo -e "this \n is\ta\ntest"
echo "**************"

num=100
#由子shell来完成,不影响当前shell中的变量
( num=999;echo "1 $num" )
echo 1:$num
#在当前shell中执行,会影响当前变量
{ num=666;echo "2 $num"; }
echo 2:$num

执行结果:
在这里插入图片描述
2.3 条件测试语句
在写shell脚本时,经常遇到的问题就是判断字符串是否相等,可能还要检查文件状态或进 行数字测试,只有这些测试完成才能做下一步动作
test命令:用于测试字符串、文件状态和数字 test命令有两种格式: test condition 或 [ condition ]
使用方括号时,要注意在条件两边加上空格
shell脚本中的条件测试如下: 文件测试、字符串测试、数字测试、复合测试 测试语句一般与后面讲的条件语句联合使用

2.3.1 文件测试

  1. 按照文件类型
    -e 文件名 文件是否存在
    -s 文件名 是否为非空
    -b 文件名 块设备文件
    -c 文件名 字符设备文件
    -d 文件名 目录文件
    -f 文件名 普通文件
    -L 文件名 软链接文件
    -S 文件名 套接字文件
    -p 文件名 管道文件
  2. 按照文件权限
    -r 文件名 可读
    -w 文件名 可写
    -x 文件名 可执行
  3. 两个文件之间的比较
    文件1 -nt 文件2 文件1的修改时间是否比文件2新
    文件1 -ot 文件2 文件1的修改时间是否比文件2旧
    文件1 -ef 文件2 两个文件的inode节点号是否一样,用于判断是否是硬链接

代码示例:

#! /bin/bash

echo "please input a filename >>> "
read FILE

test -e $FILE
echo "存在?$?"

test -s $FILE
echo "非空?$?"

[ -r $FILE ]
echo "可读?$?"

[ -w $FILE ]
echo "可写?$?"

[ -x $FILE ]
echo "可执行?$?"

test -b $FILE
echo "块设备文件?$?"

test -c $FILE
echo "字符设备文件?$?"

test -d $FILE
echo "目录文件?$?"

test -f $FILE
echo "普通文件?$?"

test -L $FILE
echo "软链接文件?$?"

test -S $FILE
echo "套接字文件?$?"

test -p $FILE
echo "管道文件?$?"

执行结果:
在这里插入图片描述
2.3.2 字符串测试
s1 = s2 测试两个字符串的内容是否完全一样
s1 != s2 测试两个字符串的内容是否有差异 -
z s1 测试s1 字符串的长度是否为0
-n s1 测试s1 字符串的长度是否不为0

代码示例:

#! /bin/bash

test "hello" = "hello"
echo "相等?$?"

test "hello" = "hella"
echo "相等?$?"

test "hello" != "hello"
echo "不相等?$?"

test "hello" != "hella"
echo "不相等?$?"

test -z "hello"
echo "长度是否为0?$?"

test -n "hello"
echo "长度是否不为0?$?"

执行结果:
在这里插入图片描述
2.3.3 数字测试
a -eq b 测试a 与b 是否相等
a -ne b 测试a 与b 是否不相等
a -gt b 测试a 是否大于b
a -ge b 测试a 是否大于等于b
a -lt b 测试a 是否小于b
a -le b 测试a 是否小于等于b
在这里插入图片描述

代码示例:

#! /bin/bash

echo "please input two numbers >>> "
read NUM1 NUM2

test $NUM1 -eq $NUM2
echo "相等?$?"

test $NUM1 -ne $NUM2
echo "不相等?$?"

test $NUM1 -gt $NUM2
echo "大于?$?"

test $NUM1 -ge $NUM2
echo "大于等于?$?"

test $NUM1 -lt $NUM2
echo "小于?$?"

test $NUM1 -le $NUM2
echo "小于等于?$?"

执行结果:
在这里插入图片描述
2.3.4 复合测试
第一种形式:命令执行控制
&&: command1 && command2 &&左边命令(command1)执行成功(即返回0)shell才执行&&右边的命令 (command2)
|| :command1 || command2 ||左边的命令(command1)未执行成功(即返回非0)shell才执行||右边的命令 (command2)

第二种形式:多重条件判定
在这里插入图片描述
代码示例:

#! /bin/bash

num=100

#判断 0 <= num <= 200
#test $num -ge 0 && test $num -le 200
test $num -ge 0 -a $num -le 200
echo "$?"

#判断 num <= 0 或者 num >= 200
test $num -le 0 || test $num -ge 200
echo "$?"

file="file.txt"

#判断文件是否不是普通文件
test ! -f $file
echo "$?"

#判断文件是否存在并且是否是目录文件
test -e $file && test -d $file
echo "$?"

执行结果:
在这里插入图片描述
2.4 控制语句
2.4.1 if语句
格式一:

if [ 条件1 ];then 
   执行第一段程序
else
   执行第二段程序 
fi

格式二:

if [ 条件1 ];then 
    执行第一段程序 
elif [ 条件2 ];then 
    执行第二段程序 
else
    执行第三段程序
fi

代码示例:

#! /bin/bash

echo "please input a number >>> "
read NUM

#注意:赋值时,等号两边不能加空格
#      []里面存放表达式时必须加空格

#一般形式
if [ $NUM -gt 50 ];then
	echo "NUM > 50"
fi

if [ $NUM -gt 50 ]
then
	echo "NUM > 50"
else
	echo "NUM <= 50"
fi

echo "***********************"

#阶梯形式
if [ $NUM -gt 50 ]
then
	echo "NUM > 50"
elif [ $NUM -lt 50 ]
then
	echo "NUM < 50"
else
    echo "NUM = 50"
fi

echo "***********************"

#嵌套形式
if [ $NUM -gt 50 ]
then
	echo "NUM > 50"
elif [ $NUM -eq 50 ]
then
	echo "NUM = 50"
else
	echo "NUM < 50"
	if [ $NUM -gt 30 ]
	then
		echo "NUM > 30"
	else
		echo "NUM <= 30"
	fi
fi

执行结果:在这里插入图片描述
2.4.2 case语句

case $变量名称 in 
“第一个变量内容”) 
    程序段一 
    ;; 
“第二个变量内容”) 
    程序段二
    ;; 
*) 
    其它程序段 
    ;;
esac

代码示例一:

#!/bin/bash
echo "This script will print your choice"

case "$1" in
	"one")
		echo "your choice is one"
		;;
	"two")
		echo "your choice is two"
		;;
	"three")
		echo "Your choice is three"
		;;
	*)
		echo "Error Please try again!"
		;;
esac

echo "hello world"

执行结果一:
在这里插入图片描述
代码示例二:

#!/bin/bash

echo "Please input your choice:"
read choice

case "$choice" in
	Y | yes | Yes | YES)
	echo "It's right"
	;;
	# *是一个通配符,可以匹配任意字符并且数量不限
	# N* 只要是N开头的,都会执行下面的命令
	N* | n*)
	echo "It's wrong"
	;;
	*)
	exit 1
esac

执行结果二:
在这里插入图片描述
2.4.3 for语句
形式一:

for (( 初始值; 限制值; 执行步阶 )) 
do 
    程序段 
done 

代码示例:

#!/bin/bash

#声明sum变量是一个整数变量,准备保存整数
declare -i sum

for (( i=1; i<=100; i++ ))
do
	sum=sum+i
done

echo "The result is $sum"

执行结果:
在这里插入图片描述
形式二:

for var in con1 con2 con3 ... 
do 
    程序段
done 

第一次循环时,$ var的内容为con1
第二次循环时,$ var的内容为con2
第三次循环时,$ var的内容为con3

当in后面所有的值都赋值完毕并执行命令后,循环结束

代码示例一:

#!/bin/bash

#注意:for循环后的变量之前不能加$
for i in 1 2 3 4 5 6 7 8 9
do
	echo $i
done

执行结果一:
在这里插入图片描述
代码示例二:

#!/bin/bash
for name in `ls`
do
	if [ -f $name ];then
		echo "$name is file"
	elif [ -d $name ];then
		echo "$name is directory"
	else
		echo "^_^"
	fi
done


执行结果二:
在这里插入图片描述
2.4.4 while语句

while [ condition ] 
do 
    程序段 
done 

当condition成立的时候进入while循环,直到condition不成立时才退出循环。

代码示例:

#!/bin/bash

declare -i i
declare -i s

while [ "$i" != "101" ]
do
	s+=i;
	i=i+1;
done

echo "The count is $s"

执行结果:
在这里插入图片描述
2.4.5 until语句

until [ condition ] 
do 
    程序段 
done 

这种方式与while恰恰相反,当condition成立的时候退出循环,否则继续循环。

代码示例:

#!/bin/bash

declare -i i
declare -i s

#until循环,是循环条件不成立,执行命令体,如果条件为真,则循环结束
until [ "$i" = "101" ]
do
	s+=i;
	i=i+1;
done

echo "The count is $s"

执行结果:
在这里插入图片描述
2.4.6 break、continue
同c语言一样

代码示例:

#! /bin/bash

for ((num=1; num<=10; num++))
do	
	if [ $num -eq 5 ]
	then
		#break退出整个循环
		#break

		#continue退出本层循环,当执行到continue的位置时,循环下方的代码不在执行
		#但是接着下个循环继续执行
		continue
	fi

	echo "num = $num"
done

执行结果:
在这里插入图片描述
2.5 函数
有些脚本段间互相重复,如果能只写一次代码块而在任何地方都能引用那就提高了代码的可重用性。
shell 允许将一组命令集或语句形成一个可用块,这些块称为 shell 函数。
2.5.1 函数的定义和调用
定义函数的两种格式:
格式一:

函数名() { 
 命令 ... 
} 

格式二:

function 函数名() { 
 命令 ... 
}

所有函数在使用前必须定义,必须将函数放在脚本开始部分

调用函数的格式为: 函数名 参数1 参数2……

代码示例:

#! /bin/bash

#定义一个函数
#由于shell中没有主函数一说,所以一般函数都需要定义在整个代码的最上边,下方对其进行调用
myfun()
{
    echo "hello world"
	echo "nihao beijing"
}

#函数的调用
myfun
myfun
myfun

执行结果:
在这里插入图片描述
2.5.2 函数传参
使用参数同在一般脚本中使用特殊变量 $1,$2 …$9一样

代码示例:

#! /bin/bash

myadd()
{
    #shell函数传参
    #shell函数中想要传参,不能在函数名后的括号里面定义
    #而是使用$1 $2 ...保存外部传入的值
    A=$1
    B=$2

	SUM=`expr $A + $B`
	echo "$A + $B = $SUM"
}

#带参数的shell函数的调用
myadd 100 200

num1=666
num2=777
myadd $num1 $num2

执行结果:
在这里插入图片描述
2.5.3 函数返回值
函数可以使用return 提前结束并带回返回值

代码示例:

#! /bin/bash

myadd()
{
    A=$1
    B=$2

    SUM=`expr $A + $B`

	return $SUM
}

myadd 10 20
#函数的返回值一般通过$?可以获取到,但是$?获取到的最大值是255,如果超过这个值,会出错
echo "$?"

myadd 100 200
#echo "$?"
#在shell中,除了()中定义的变量,只要不做任何修饰,
#都可以认为是全局变量,可以再任意一个位置调用
echo "SUM = $SUM"

执行结果:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值