shell语法

shell 概述

是什么

shell 是一门计算机语言,和 python | Java一样,都可以编写程序
shell字面意思:,:指操作系统,shell 是保护操作系统的 。
计算机操作系统只能识别 0 和 1组成的机器码,现在我们是通过GUI|CLI 来间接操作操作系统
GUI(图形化界面) | CLI(命令行) 在用户与操作系统之间,相当于桥梁、中介的作用,结构上看,GUI和CLI 保护操作系统
GUI 与 CLI 就是通过 Shell 实现的

分类 

第一类:GUI样式的shell(图形化界面)
第二类:CLI样式的shell(命令行)
专指: Linux 下的 shell 编程

怎么用

流程
1)、创建一个文本文档,后缀名是 .sh
文档名要做到见名知意
2)、再在文本文件中录入一个命令
echo  "xxxx" 在命令行模式下直接输出数据
规范:第一行固定格式 #!/bin/bash  指定shell解析器在linux位置
作用:指定脚本解析的解释器
3)、执行  .sh 文件(shell 脚本)
方式1: sh(bash) shell文件
方式2: 绝对路径(/xxx/yyy/abc.sh) 或 相对路径(./abc.sh),注意:要修改文件的权限 chmod 777 abc.sh
方式3: source abc.sh(source 相当于 ./)
01.sh
#! /bin/bash
#指定脚本解析的解释器
#echo 是将结果输出到终端上
echo "我是孙腾"
执行shell脚本

练习

练习1:在命令行输出当前所在目录
02.sh
#! /bin/bash
#指定脚本解析的解释器
pwd
执行shell脚本

shell语法变量和运算符

注释

单行注释(常用):一次只注释一行
格式: # 注释文本

变量

<u>变量创建:</u>

	格式: 变量名=变量值

	注意1:变量名

	a)、不能数字开头

	b)、变量名不能有空格这种特殊字符

	c)、起名做到见名知意

	d)、变量名不要使用关键字

	注意2:赋值符号"="左右两侧不要有空格
注意3:变量值

	a)、变量值可以不使用引号,但是如果有空格,必须使用 "" or ''

	b)、"" 和 '' 的区别,变量之间赋值时,如果是  "",那么赋的是变量的值,如果是 '' 只是赋值调用格式
变量查询
	格式:"${变量名}" -----  标准格式  打印时在写代码时候 一定要用双引号这个格式,不然会报莫名错误
	注意:其他格式(不建议使用)
	${变量名} or $变量名
变量修改:
    格式:同增
    变量名=变量值
变量删除:
    格式:unset 变量名

变量分类

本地(局部)变量
只有当前 shell 可以使用的变量	 
全局变量(静态变量)(了解)
被多个 shell 共享的变量	(只能在一个终端窗口,不能跨终端,跨终端的env里面没有全局变量) 
需求:如何将本地变量转换成全局变量
思想:将本地变量设置为全局变量就是要将本地变量导出到共享空间
格式: export 局部变量 
查询全局变量: env
注意1:如果是全局变量,建议变量名所有字母都大写
注意2:全局变量要慎用
变量(特殊变量)
需求:编写shell动态获取某个目录下的子级(目录不一定)
实现流程:
    1)、shell 调用时,可以传入要操作的目录
    格式: sh abc.sh 某个目录
    2)、shell 执行时,可以获取调用传入的目录
    格式:ls  $1 (代表传入的第一个参数)      
上述流程其实就是传参以及参数解析的过程,这个参数就可以称之为内部变量
语法总结:
应用场景,程序执行时有些数据是可变的,可以调用脚本时,传入这些可变数据,脚本中解析获取
调用格式: sh xxx.sh 参数1 参数2 参数3 .....
解析格式: $N 获取第 N 个参数
优点: 动态传值,更灵活
$0 获取脚本文件名
$* 获取所有参数
$# 获取参数个数
inner.sh
#! /bin/bash
#ls $1
echo "第1个参数$1"
echo "第2个参数$2"
echo "第3个参数$3"
echo "第9个参数$9"
echo "第10个参数$10"
echo "$0"
echo "$*"
echo "$#"
执行

练习:动态获取值

扩展:读取键盘录入
需求:编写shell动态获取某个目录下的子级(目录不一定,要让调用者指定)
格式: read     -p     "提示语句:"     变量名 (注意:有空格!!!!)
作用:执行到此时,程序挂起,等待用户录入数据,录入数据后,回车,录入的数据会赋值给变量
优点:动态获取数据,更灵活!!!!!
read.sh
#! /bin/bash
#1、用户录入目录
read -p "请输入一个目录:" myDir
#2、 获取目录子级
ls "${myDir}"
执行 

变量特殊赋值(记住)

需求:将某个命令的结果赋值给一个变量
格式:变量名=`命令`

练习

使用shell脚本,输出当前所在的目录
知识点:将命令结果赋值给变量
shell脚本
#! /bin/bash
dir=`pwd`
echo "当前所在目录是:${dir}"
执行shell脚本
计算指定目录下有多少个文件,用shell脚本实现
新知识点:获取某个目录下子级个数
        固定格式:ls 目录 | wc -l
参数shell脚本
#! /bin/bash
#动态获取某个目录,然后在获取目录下子级的个数
#方案一:读取脚本调用时传入的参数
#调用 sh test03.sh /root
#执行 ls $1 | wc -l
count=`ls $1 | wc -l`
echo "$1目录下的子级:${count}"
执行
键盘录入shell脚本
#! /bin/bash
#动态获取某个目录,然后在获取目录下子级的个数
#方案一:读取键盘录入的数据
read -p "请你输入一个路径" myDir
# 获取目录子级个数
count=`ls ${myDir} |wc -l`
echo "${myDir}下的子级个数为:${count}"
执行

运算符

算数运算符
    格式: $((数学表达式))
    运算符:	+ - * / % == 加减乘除取余
    注意: 一般计算机语言中除法运算只取商   
比较运算符
    返回的是 boolean 值(特殊: 0为true 1为false)
    格式: [ 表达式 ] ---- 注意:[] 中有两个空格,两个空格中添加表达式
    查看结果: $? 
    运算符: 不能直接使用 > < >= <= == != 
    使用对应的参数  -gt(>) -lt(<) -ge(>=) -le(<=) -eq(==) -ne(!=) **记住**
逻辑运算符
    返回 boolean 值(<u>特殊: 0为true 1为false</u>)
    格式: [ 表达式 ]
    运算符: -a 与  -o或 	!非     
字符串比较:返回 boolean 值
    格式: [ 表达式 ]

运算符: == 判断两个字符串内容是不是一样
	      != 判断两个字符串内容是不是不一样
	      -z 判断单个字符串长度是不是0(判断字符串是不是空)
文件判断:返回 boolean 值
        格式: [ 表达式 ]
        运算符:  -d: 判断是不是文件夹
        -f: 判断是不是文件
        -e: 判断是不是存在
#常用的文件测试操作符
#常用操作符                        #说明
-f 文件,全称file            #文件存在且为普通文件则为真,表达式成立
-d 文件,全称directory       #文件存在且为目录则为真,表达式成立
-s 文件,全称size            #文件存在且大小不为0为真
-e 文件,全称exist           #文件存在则为真
-r 文件,全称read            #文件存在且为可读则为真,表达式成立
-w 文件,全称write           #文件存在且可写为真,表达式成立
-x 文件,全称executable      #文件存在且可执行为真
-L 文件,全称link            #文件存在且为链接文件为真
f1 -nt f2,英文newer than    #文件f1比文件f2新则为真,根据文件修改时间计算
f1 -ot f2,英文older than    #文件f1比文件f2旧为真,根据修改时间计算

练习

判断 /home/admin(/root)目录是否为空
思路:现获取目录子级文件个数,判断是否大于 0
#! /bin/bash
#统计指定目录文件个数
read -p "请输入要统计的目录:" str
count=`ls ${str} | wc -l`
echo "${str}目录下共有${count}"

shell语法函数

shell函数常用方式

1. 简单函数(无参)
2. 带参函数(调用函数时带参数)
3. 带参函数(执行脚本时调用参数)

简单函数

说明:自定义函数,调用函数名

格式

定义函数:
    函数名(){
        语句
        ...
    }
调用函数:
    函数名
案例1
需求:定义fun01函数,打印 this is a funcation
#! /bin/bash
#声明一个函数
hello(){
	echo "hello function!"
}
#调用函数
hello
执行

带参函数(调用函数时带参数)

说明:调用函数名时带参数

格式

定义函数:
    函数名(){
        语句$n
        ...
    }
调用函数:
    函数名 参数
需求:定义fun01函数,调用的时候传递参数,在函数内部获取参数
#! /bin/bash
# 有参数的函数
getSum(){
	echo "两个数字的和为:$(($1+$2))"
	echo "第一个参数 $1"
	echo "第二个参数 $2"
	echo "第三个参数 $3"
	echo "第十参数 $10"
	echo "文件名:$0"
	echo "所有参数:$*"
	echo "参数个数:$#"
}
# 调用函数
getSum 4 2 3 4 5 6 7 8 9 a b
结果

带参函数(执行脚本时调用参数)

说明:执行脚本时附带参数

格式

定义函数:
    函数名(){
        语句$n
        ...
    }
调用函数:
    函数名 $n
案例
需求:定义fun01函数,执行脚本时传递参数 lisi,打印:nihao lisi
#!/bin/bash
# 定义函数名
fun01(){
     echo "ni hao $1"
}

# 调用函数
fun01 $1
# 执行脚本调用
# bash /root/fun03.sh lisi

带返回值的函数

#! /bin/bash
#带返回值的函数
#1、声明函数
getSum(){
	result="$(($1+$2))"
	#return "${result}"
	echo "函数中的result:${result}"
	return 0
}
#2 调用函数
getSum 3 4
#打印返回值
echo "函数返回的结果是:$?"
echo "函数外调用result:${result}"

函数加强练习

使用函数实现,输入任意两个数,打印求和结果
#! /bin/bash
#带返回值的函数
#1、声明函数
getSum(){
	result="$(($1+$2))"
	#return "${result}"
	echo "函数中的result:${result}"
	return 0
}
#2 调用函数
getSum 3 4
#打印返回值
echo "函数返回的结果是:$?"
echo "函数外调用result:${result}"
###### 读取键盘录入,录入长方形的长和宽,编写求周长和面积的函数,调用并输出周长和面积的值
#! /bin/bash
#1读取键盘录入的长和宽
read -p "请输入长:" length
read -p "请输入宽:"  width
#2求周长函数
getAllLength(){
	echo "周长是:$((($1+$2)*2))"
}
#3求面积函数
getArea(){
	echo "面积是:$(($1*$2))"
}

#调用周长函数
getAllLength "${length}" "${width}"
#调用面积函数
getArea "${length}" "${width}"
说明:使用函数;提示输入一个目录,在此目录中进行提示要创建的文件名;如果该目录不存在,提示目录不存在;
          如果输入的文件已存在,提示该文件已存在,否则创建该文件;
#! /bin/bash
#处理文件的函数
doMyFile(){
	#开始处理
	#文件存在,给出提示,不存在就创建
	if [ -f $1 ]
	then
		echo "文件已经存在了"
	else
		echo "文件开始创建"
		echo "......"
		touch $1
		echo "文件创建完毕"
	fi
}
#处理目录的函数
doMyDir(){
	#获取传入的目录$1
	#如果不是目录给出提示,是目录操作文件
	if [ -d $1 ]
	then
		echo "操作文件"
		# 让用户录入文件名
		read -p "请你录入一个文件:" myFile
		# 进入目录
		cd $1
		#操作文件
		doMyFile ${myFile}		
	else
		echo "你输入的不是目录"
	fi
}
read -p "请你输入一个目录:" myDir
#操作目录,单独一个函数实现
doMyDir ${myDir}

shell流程控制

说明:如果条件成立,则执行then后面语句,否则执行else后面语句
格式:
    if [ 条件 ]
    then
        语句块
    else
        语句块
    fi
提示:
    1. []中括号在shell中表示为表达式,表达式前后必须有空格;如[ 1 -gt 0 ]
    2. 条件中有变量或字符串使用""括起来
    3. then可以和if语句写在一行,then语句之前需要添加; 如:if [ 条件 ];then
    4. 结尾有关键字fi

if流程控制语句

需求: 录入年龄,判断是否成人,如果成人了输出"成年人"
#! /bin/bash
#if单分支实现
#1 让用户录入年龄
read -p "让用户录入你的年龄" age
#2 年龄判断
if [ ${age} -ge 18 ]
then
	echo "成年人"
fi

if..else流程控制语句

(需求: 录入年龄,判断是否成人,如果成人了输出"成年人",否则输出未成年)
#! /bin/bash
#if多分支实现
#1 让用户录入年龄
read -p "让用户录入你的年龄" age
#2 年龄判断
if [ ${age} -ge 18 ]
then
	echo "成年人"
else
	echo "未成年人"
fi

if...elif多分支控制语句

#! /bin/bash
#if多分支实现
#1 让用户录入年龄
read -p "让用户录入你的年龄" age
#2 年龄判断
if [ ${age} -lt 18 ]
then
	echo "未成年人"
elif [ ${age} -ge 18 -a ${age} -le 30 ]
then
	echo "成年人"
elif [ ${age} -gt 30 -a ${age} -lt 50 ]
then
	echo "中年人"
else
	echo "老年人"
fi

练习

练习1:判断用户输入的用户名和密码是否为admin 123456,如果是则提示登录成功,否则提示失败
#! /bin/bash
read -p "输入用户名" username
read -p "输入密码" passwd
if [ ${username} == "admin" -a ${passwd} == "123456" ]
then
	echo "登陆成功"
else
	echo "登陆失败"
fi
练习2:输入数字,判断是否大于0,如果大于0则将该数字-1并输出,否则+1输出
#! /bin/bash
read -p "请你录入一个数字" num
# 如果数字小于0减1 否则加1
if [ ${num} -gt 0 ]
then
	num=$((${num} + 1))
	echo "${num}"
else
	num=$((${num} - 1))
	echo "${num}"
fi
练习3:判断用户输入的目录是否存在,如果存在则统计目录下的文件个数,否则提示用户该目录不存在
#! /bin/bash
read -p "请输入一个目录:" myDir
if [ -d ${myDir} ]
then
	# 统计文件个数
	count=`ls ${myDir} | wc -l`
	echo "${myDir}目录下文件个数是:${count}"
else
	echo "你输入的目录不存在"
fi
练习3:判断用户输入的内容是否为空,为空则提示,不为空则判断是否为目录,不为目录则判断是否为文件,否则提示错误信息
#! /bin/bash
read -p "请你输入一个文件或目录" myfile
if [ -z ${myfile} ]
then
	echo "录入的路径不能为空"
elif [ -f ${myfile} ]
then
	echo "录入的路径是文件"
elif [ -d ${myfile} ]
then
	echo "录入的路径是文件夹"
else
	echo "录入的路径有误"
fi

流程控制分支实现之case

条件符合执行相应的代码块,类似于if..elif..语句

格式:
    case 变量 in
        值1 )
            echo "语句块1"
            ;;
        值2 )
            echo "语句块2"
            ;;
        值3 | 值4 )
            echo "语句块3"
            ;;
        ...
        * )
            echo "语句块4-默认值"
            ;;
        esac
提示:
    1. 星号(*)相当于else,条件都不符合时执行;
    2. 双分号(;;)是必须的,执行完相应语句块跳出程序;
    3. 竖线(|)用于分割多个值,相当于 值1 or 值2 ;
    4. 值可以为字符串、数字、区间值( [0-9] | [a-z] | [A-Z] )、组合词[aA][bB][cC]
    4. 结尾必须有esac
需求:模拟游戏级别选择,读取键盘录入的数字,如果是数字1,那么输出简单,    如果是数字2,那么输出一般,如果是数字3输出困难,其他输出数据有误
#! /bin/bash
read -p "请输入一个数据:" num
case "${num}" in
1)
	echo "游戏难度简单"
	;;
2)
	echo "游戏难度一般"
	;;
3)
	echo "游戏难度困难"
	;;
*)
	echo "你输入的数据有误"
	;;
esac

shell 语法:流程控制循环实现之for

遍历读取列表元素,列表元素遍历完毕,结束语句;

语法格式:
for 值 in 列表
do
    执行语句
done

练习

需求:遍历 1-10之间所有整数
#! /bin/bash
# 循环遍历
#for ele in 1 2 3 4 5 6 7 8 9 10
#for ele in `seq 10`
#for ele in `seq 5 10`
for ele in `seq 5 2 10`
do
	echo "元素:${ele}"
done
注意
seq 命令优化 for 循环
格式1: seq 参数NUM ---> 默认遍历 [1-NUM] 之间的所有整数
格式2:    seq 参数NUM1 参数NUM2 ----> 遍历 [NUM1-NUM2]之间的所有整数
格式3:    seq 参数NUM1 参数NUM2 参数NUM3 ----> 遍历 [NUM1-NUM3] 之间的整数,但是每次递增 NUM2 值
	       不指定 NUM2 每次默认递增1, NUM2 又称之为步进值
求1-100之间的和
#! /bin/bash
#计算1-100之间的整数和
sum=0
for ele in `seq 100`
do
	sum=$((${sum}+${ele}))
done
# 输出变量的值
echo "1-100之间的和是:${sum}"

shell 语法:流程控制循环实现之while

	while [ boolean表达式 ]

	do

		code.....

	done

(需求:遍历 1-10之间所有整数)
#! /bin/bash
#while循化遍历1-10
num=1
while [ ${num} -le 10 ]
do 
	echo "${num}"
	num=$((${num}+1))
done
求1-100之间的和
#! /bin/bash
#!while循环求1-100的整数和
sum=0
num=1
while [ ${num} -le 100 ]
do
	sum=$((${sum}+${num}))
	num=$((${num}+1))
done
#循环结束
echo "1-100整数和是:${sum}"

shell 语法其他:重定向

是什么?
可以将命令产生的数据保存到磁盘文件
为什么?
一种序列化(持久化)机制,可以持久的保存数据
怎么用?
格式1: 命令 1>> 磁盘文件 (将正常命令的结果输出到文件) 
格式2: 命令 2>> 磁盘文件 (将错误命令的结果输出到磁盘文件)

shell 语法其他:数组

是什么?
数组也是变量,但是是特殊的变量,一般变量只能存储一个值,而数组可以存储多个值
怎么用?
数组创建
	变量名=(值1 值2 值3 .... )
数组查询
    查某个元素: ${数组名[索引 ]} //索引从 0 开始
    查询所有元素: ${数组名[*]} | ${数组名[@]}
    查询元素个数: ${#数组名[*]} | ${#数组名[@]}
数组修改
    变量名[索引]=新值
    数组删除
    unset 数组名(同变量删除)

原文地址:https://www.cnblogs.com/st998/p/13825218.html