Skip to content

备课😳,复习(预习)一下shell脚本的基本语法。

shell基本语法


shell脚本可以将完成一个任务的所有命令按照执行的先后顺序,自上而下地写入到一个文件,并给予执行权限。

脚本运行方法

  • 赋予运行权限
  • 使用bash执行
shell
chmod +x demo.sh
./demo.sh

# 或者 
bash demo1.sh

shell常用符号

~:			# home 目录
!: 			# 执行历史命令,!! 执行上一条命令
$:			# 变量取内容符,$USER
+ - * / % 		# 加减乘除
&:			# 后台运行
*:			# 通配符,匹配所有
?:			# 通配符,匹配除回车外的一个字符
;:			# 一行执行多个指令的时候用作分割
|:			# 管道符,将上一个命令的输出作为下一个命令的输入
\:			# 转义字符
``:			# 反引号,在命令中执行命令,可类比于python中的exec()函数
':			# 单引号,shell中的字符串需要使用 单引号括起来,与双引号不同的是单引号不解释变量 '$USER'
":			# 双引号,脚本中出现的字符可以使用双引号括起来 "$USER" 会解释变量
>:			# 输出重定向符  只用一个 > 会覆盖文件 ,用两个 >> 会追加文件
<:			# 输出重定向符,只用一个 就是只输入一次,两个 << 就是追加输入(可以用于交互式的命令输入例如fdosk),使用 <<EOF表示结束书输入
$?:			# 通过上一个命令的 exit code判断上一条命令是否执行成功,为0则代表执行成功,否则为执行失败。expr 1 + 1 &>/dev/null; echo $?可以用分号分隔上一个命令,从而达到判断执行是否成功的作用

shell 数学运算

shell中完成数学运算的方式有很多种

  • expr表达式
  • let表达式。
  • (())表达式

注意1:expr 表达式中运算符的前后必须要有空格

注意2:expr 表达式中使用乘运算符 * 时需要使用转义符

注意3:let 表达式中=前后不能有空格

shell
# expr 表达式
expr 1 + 1
expr 1 - 1
expr 3 \* 4
expr 9 / 3
expr 10 % 3
# `let`可以完成同样的功能,但必须要一个变量缓存计算结果
let sum=1+2
# (()) 中对表达式没有要求,使用乘法时也不需要转义
echo $((1+1))
echo $((100 * 3))

当运算中需要使用小数时,可以使用管道运算符|配合bc命令完成 (bc可能需要单独安装 )

bc中使用scale=n制定保留小数的位数

shell
echo "scale=2;100/3"|bc
# 上面的输出为 33.33

echo "当前内存占用为: `echo "scale=2;100/3"|bc`%"
# 当前内存占用为 33.33%

shell退出

exit code 的范围为8位,即0-255

shell
exit 0 # 表示正常退出

echo $? # 查看上一条指令是否正常执行并退出

shell 输入输出

read命令可以从终端读入内容

shell
read acc # 将输出内容保存到 变量acc中
read -s passwd # 输出内容保存到 passwd中,且输入的时候输入内容不回显,一般用于密码输入
read -p "这里是提示:" abc #-p 指定输入时的提示
read -n6 abc # 输入的长度只能为6
read -t5 abc # 只能在 5s 内输入,超过时间后执行下一行

echo命令的作用是在显示器中输出一段提示文字。常用用法和参数如下

shell
echo "hello world!" # 普通输出,输出后换行
echo -n "hello world!" # 输出后不换行
echo -e "\t abc" # 输出字符串中包含有特殊的转义字符时使用

shell的变量

变量的分类与定义语法

shell中变量类型分为三种,其中本地和全局变量都属于环境变量。

  1. 本地变量:用户私有变量,只有本用户读取或修改,保存在.bash_profile.bashrc文件中
  2. 全局变量:所有用户都可以使用,保存在/etc/profile和/etc/.bashrc
  3. 用户自定义变量:用户自定变量,例如在脚本中定义的变量

变量名在定义时不需要加$,但是在使用的时候需要加$符号。

定义变量的格式为:变量名=值。将变量设置成全局变量的时候需要加上前缀 export

注意:变量名和等号之间不能有空格

shell
# 定义一个临时变量,在终端关闭或者重启之后该变量会被清除
VAR1=1
AGE=18
# 手动清除一个变量
unset VAR1

# 定义一个全局变量
export GENDER='MALE'

变量名最好全部写成大写以示区分

数组变量

数组可以将一系列的内容保存到同一个变量中,在访问时通过下标进行访问。

定义数组:数组名称=(元素1 元素2 元素3 ....)

各个元素之间通过空格隔开。

数组的访问 : ${数组[下标]}, 下标从0开始

注意: bash 默认下标从0开始,但是zsh的下标默认从1开始

shell
# 单个赋值
arr0[0]='abc'
arr0[1]='def'

arr1=('tom' 'jack' 'rose') # 连续赋值
arr1=(`cat /etc/passwd`) # 将文件的行读入作为一个数组

echo ${arr1[@]} # @ 符号代表数组所有的成员
echo ${#arr1[@]} # 获取数组的长度
echo ${!arr1[@]} # 打印数组的索引,备注:zsh不支持
echo ${arr1[@]:1} # 切片,从1开始的元素
echo ${arr1[@]:1:2} # 切片,从1开始访问两个元素

shell中的关联数组可以类比字典类型,可以自定义索引访问

shell
declare -A r_arr
# 连续赋值
r_arr=([name]='tom' [age]='18')
# 或者单独赋值
r_arr=([gender]='male')


# 访问关联数组
echo "${r_arr[name]}"

流程控制


常见的运算符号

shell中没有 >=,<= 之类的判断符号,整数数学的比较运算运算符有下面这些

shell
-eq				等于
-gt				大于
-lt				小于
-ge				大于或等于
-le				小于或等于
-ne				不等于

# 用法
test 1 -q 1;echo $?

常见的文件的判断运算符

shell
-d 				检查文件是否存在且为目录
-e 				检查文件是否存在
-f 				检查文件是否存在且为文件
-r 				检查文件是否存在且可读
-w 				检查文件是否存在且可写
-x				检查文件是否存在且可执行

常见的字符串比较运算

shell
==				等于
!=				不等于
-n 				检查字符串长度是否大于0
-z				检查字符串长度是否为0
# 用法
test -z ""; echo $?
test 'abc'=='bcd';echo $?

逻辑运算

shell
!				取反
&&				逻辑与
|| 				逻辑或

if 语句

if语句的格式如下,condition中可以使用前面所提到的逻辑运算符将条件连接起来

shell
if [ condition ]
then
	commands
fi


if [ condition ]
then
	commands
else
	commands
fi


if [ condition ]
then
	commands
elif [  ]
	commands
else
	commands
fi

用法举例

shell
# 可以使用 $1 ,$2 等变量获取传入的命令行参数
if [ $1 -eq $2 ]
then
	echo "等于"
else
	echo "不等于"
fi

for 循环语句

第一种for语句的语法

shell
for var in value1 value2
do
	commands
done
#例子,seq 是一个shell 命令,可以生成指定范围内的数字序列
# 1 直接赋值
for x in 1 2 3 4 5 6 7 8 9
	do
	echo ${x}
done

# 2 使用 shell 命令赋值
for var in `seq 1 9`
do 
	echo ${var}
done
# seq 的用法
# seq [start] [step] [end]
# seq [start] [end]

# 3 可以直接用字符串赋值,使用 空格分隔
for var in hello peter, i\'m Doctor Octopus
	do
	echo $var
done

第二种for语句的语法, 类似于 C语言的写法

shell
for ((i=1;i<10;i++))
	do
	echo ${i}
done
# 可以由多个条件,condition 两边记得加空格
for (( a=1,b=1;a<100;a++,b++ ))
	do
	echo "${a},${b}"
done

while 和 until 循环

while语句

shell
while condition
do
    command
done

# 例子
int=1
while(( $int<=5 ))
do
    echo $int
    let "int++"
done

until语句

shell
until condition
do
    command
done

# 用法
a=0
until [ ! $a -lt 10 ]
do
   echo $a
   a=`expr $a + 1`
done

case 语句

当有多个分支时除了可以使用if elif ...这种结构还可以使用 case语句进行分支选择

shell
case value in
pattern1)
	commands
;;
pattern2)
	commands
;;
...
*
	commands
;;
esac

# 例子
echo '输入 1 到 4 之间的数字:'
echo '你输入的数字为:'
read aNum
case $aNum in
    1)  echo '你选择了 1'
    ;;
    2)  echo '你选择了 2'
    ;;
    3)  echo '你选择了 3'
    ;;
    4)  echo '你选择了 4'
    ;;
    *)  echo '你没有输入 1 到 4 之间的数字'
    ;;
esac

循环控制

流程控制一般包含有 continuebreak语句用于控制循环的执行

shell
while		# 不加任何条件语句则表示死循环
	do
	read a
	if [ a -eq 0]
		then
		break
    elif [ a -eq 1 ]
    	continue
    else
    	echo "your number is ${a}"
    fi
done

shell函数


定义函数的语法有两种,分别为

shell
# 语法一
func_name ()
{
	commands
	return N
}

# 语法二
function func_name ()
{
	commands
	return N
}

# 函数参数例子
function hell0_func ()
{
	echo "hello $1" 	# $1 代表第一个函数参数,$0是当前的脚本文件名
}
$#						# 函数的参数个数
$?						# 最后一个命令的退出状态,为 0 表示没有错误

调用函数的方法比较奇怪,不需要加(),需要传参的话直接写在后面就可以了

shell
# 函数传参的例子
hello_func alex			

# 带返回值函数调用的例子
funWithReturn(){
    echo "这个函数会对输入的两个数字进行相加运算..."
    echo "输入第一个数字: "
    read aNum
    echo "输入第二个数字: "
    read anotherNum
    echo "两个数字分别为 $aNum$anotherNum !"
    return $(($aNum+$anotherNum))
}
funWithReturn
echo "输入的两个数字之和为 $? !"

最新更新: