目录
shell语法基础
指定shell解析器
注释
运行
变量
定义变量
引用变量
清除变量值
从键盘获取值
输入单值
添加输入提示语
读取多值
编辑
定义只读变量
环境变量
设置环境变量与查看环境变量
特殊变量
三种引号的作用与区别
小括号与大括号
参数传递
位置参数传递
选项参数传递
获取参数相关信息
其余预设变量
字符串处理
条件测试
文件测试
字符串测试
数值测试
控制语句
逻辑语句
条件语句
if语句
case语句
循环语句
for循环
while循环
函数
函数定义
函数的调用与返回
文件导入
shell语法基础
指定shell解析器
#!/bin/bash
#!用来声明脚本由什么shell解释,否则使用默认shell
shell终端有多种,我们大部分用的是sh或者bash,其中sh是最原始的shell,而bash不完全兼容sh,查看系统可用的shell终端可用以下命令
vim /etc/shells
/bin/sh
/bin/bash
/bin/rbash
/bin/dash
/usr/bin/tmux
/usr/bin/screen
注释
#
运行
shell脚本有三种执行方式
- ./xxx.sh
- ./xxx.sh :先按照 文件中#!指定的解析器解析
如果#!指定指定的解析器不存在 才会使用系统默认的解析器
- bash xxx.sh
- bash xxx.sh:指明先用bash解析器解析
如果bash不存在 才会使用默认解析器
- . xxx.sh
- 直接使用默认解析器解析(不会执行第一行的#!指定的解析器)但是第一行还是要写的
三种执行情况:
打开终端就会有以后个解释器,我们称为当前解释器
我们指定解析器的时候(使用 ./xxx.sh 或 bash xxx.sh)时会创建一个子shell解析 脚本
变量
定义变量
变量名=变量值
如:num=10
引用变量
$变量名
清除变量值
unset
从键盘获取值
read命令可以从键盘获取值
输入单值
#!/bin/bash
echo "--------"
read data
echo "data=$data"
运行结果
添加输入提示语
使用read命令的-p选项可以添加输入提示语
#!/bin/bash
echo "--------"
read -p "please input the value of data:" data
echo "data=$data"
读取多值
#!/bin/bash
read -p "please input the value of data1 and data2 >>> " data1 data2
echo "data1 is ${data1} and the data2 is ${data2}"
注意,输入时以空格作为分隔符,运行结果如下:
定义只读变量
readonly关键字可标识一个变量为只读变量
#!/bin/bash
readonly num=10
echo "num=$num"
num=20
echo "after num=$num"
环境变量
设置环境变量与查看环境变量
创建一个test.sh脚本,并写下
#!/bin/bash
export MY_DATA=42
退出保存,然后在终端中输入
source ./test.sh
然后在终端中输入
上述过程解析
- export关键字用于定义一个环境变量
- source命令用于将脚本中的环境变量生效,生效后的作用就是让其他脚本可识别该变量
- 因此,假如我们重新定义一个新的脚本,输入echo MY_DATA,是可以输出该值的
- env命令用于列出所有的环境变量
特殊变量
三种引号的作用与区别
- 双引号:可以解析变量的值
- 单引号:不能解析变量的值,直接将单引号中的内容作为字符串处理
- 反引号(数字键1前的按键):引用系统命令
#!/bin/bash
num=42
echo "num=$num"
echo 'num=$num'#直接将$num作为字符串处理。并不会解析num的值
echo "date is `date`"
上述代码的运行结果如下所示
小括号与大括号
- ():由子shell完成,不会影响当前shell的值
- {}:由当前shell完成,通常用于作为变量引用的边界
#!/bin/bash
data=42
(
#以下内容由子shell完成,不会影响外边data的值
data=43
echo "内部data值为:$data"
)
echo "外部data值为:$data"
#使用{}将data变量的引用与外部的eee三个字符区分开
echo "${data}eee"
echo ">>>>>>>"
echo "$dataeee"
运行结果
因此,一个好的习惯应当是,在引用变量的时候,使用{}将其包裹
参数传递
位置参数传递
shell中用$1、$2、$3来传递外部的第一个参数、第二个参数、第三个参数等等,该参数传递方式称为位置参数传递
创建一个test.sh脚本,内容定义如下
#!/bin/bash
echo "第一个参数值:$1"
echo "第二个参数值:$2"
echo "第三个参数值:$3"
保存退出,在命令行中执行脚本,并传递参数
./test.sh 42 43 45
运行结果为
选项参数传递
如果想实现选项参数传递,而不依赖于位置,可参考
shell脚本实现长短项参数设置_shell脚本处理长参数-****博客
获取参数相关信息
- $#:获取传入的参数个数
- $@:获取所有的参数内容,其中每个参数都会作为独立的字符串处理,假设输入参数是
one two three
,使用"$@"
会得到"one"
、"two"
、"three"
三个独立的参数。- $*:获取所有的参数内容,并将所有参数作为一个整体处理。输入参数
one two three
,使用"$*"
会得到"one two three"
,成为一个单一字符串。
#!/bin/bash
echo "第一个参数值:$1"
echo "第二个参数值:$2"
echo "第三个参数值:$3"
echo "the number of all parms is: $#"
echo "all parms value is: $@"
echo "all parms value is: $*"
for parm in "$@"; do
echo "${parm}"
done
for parm in "$*"; do
echo "${parm}"
done
运行结果
其余预设变量
- $?:获取命令执行后返回的状态,0表示执行成功,无错误,非0表示执行失败,有错误
- $0:获取当前执行的进程名
- $$:获取当前执行的进程号
代码实例
#!/bin/bash
function func1(){
#返回非0状态,表示func1函数执行出错
return 1
}
function func2(){
#获取传递给func2的参数
parm1=$1
parm2=$2
echo "parm1 is ${parm} and the parm2 is ${pamr2}"
#返回0,表示func2函数执行无误
return_value="yes"
echo ${return_value}
return 0
}
func1
echo "func1 return status is $?"
func2 42 43
echo "func2 return status is $?"
return_value=$(func2 54 56)
echo "func2 return status is $? ,and the return value is $return_value"
上述代码解析:
- function关键字用于定义一个函数
- shell中的return关键字是返回函数执行状态的,return后的值只能是数字,不能是其余字符串信息
- 如果想返回函数体内的值给函数外部执行者,使用echo命令
- shell中函数参数的传递,同样也使用上述的位置参数传递
执行结果
获取进程名与进程号
#!/bin/bash
echo "process name is $0"
echo "process number is $$"
字符串处理
#!/bin/bash
str="hello hello world"
#获取
echo "字符串长度:${#str}"
#从下标为3的字符开始截取子串
echo "${str:3}"
#从下标为3的字符开始截取长度为4的子串
echo "${str:3:4}"
#将字符串中的第一个hello替换为hahaha
new_str="${str/hello/hahaha}"
echo "$new_str"
#将字符串中的所有hello替换为hhhhh
new_str1="${str//hello/hhhhh}"
echo "$new_str1"
条件测试
条件测试使用[ condition ]判断condition是否为真
使用方括号时,要注意在条件两边加上空格,同时,运算符和操作数之间必须有空格。缺少空格会导致语法错误。
文件测试
判断文件状态
- -e:判断文件是否存在
- -d:判断文件是否是一个目录
- -f:判断文件是否是一个文件
- -s:判断文件是否非空
- -r:判断文件是否可读
- -w:判断文件是否可写
- -x:判断文件是否可执行
- -L:判断该文件是否是符号链接
- -c:判断是否是字符设备
- -b:判断是否是块设备
#!/bin/bash
for item in `ls`; do
if [ -d "$item" ]; then
echo "$item 是一个目录"
elif [ -f "$item" ]; then
echo "$item 是一个普通文件"
else
echo "$item 是其他类型"
fi
done
字符串测试
- =:判断两个字符串是否相等
- !=:判断两个字符串是否不相等
- -z:判断是否是空串
- -n:判断是否是非空串
#!/bin/bash
read -p "str1=" str1
read -p "str2=" str2
#如果str1和str2都不为空
if [[ ! -z ${str1} && ! -z ${str2} ]];then
echo "$str1"
echo "$str2"
#如果str1和str2的值相等
if [ "$str1" = "$str2" ]; then
echo "str1 equal str2"
else
echo "str1 not equal str2"
fi
fi
数值测试
#!/bin/bash
read -p "num1=" num1
read -p "num2=" num2
if [ $num1 -eq $num2 ]; then
echo "$num1 equal $num2"
elif [ $num1 -gt $num2 ];then
echo "$num1 greater than $num2"
else
echo "$num1 less than $num2 "
fi
控制语句
逻辑语句
- 与运算:&&
- 或运算:||
- 非运算:!
条件语句
if语句
使用格式如下:
if [条件1]; then
执行第一段程序
elif [条件2];then
执行第二段程序
else
执行第三段程序
fi
结合上述字符串测试与数值测试案例学习即可
case语句
#!/bin/bash
read -p "please input choice yes or no >>> " choice
case $choice in
yes | y* | Y*)
echo "yes"
;;
no | n* | N*)
echo "no"
;;
*)
echo "others"
;;
esac
循环语句
for循环
#!/bin/bash
read -p "please input n is >>> " n
declare -i sum=0
declare -i i=0
for ((i=0;i<n;i++))
do
sum=$sum+$i
done
echo "sum=$sum"
for item in `ls`; do
if [ -d "$item" ]; then
echo "$item 是一个目录"
elif [ -f "$item" ]; then
echo "$item 是一个普通文件"
else
echo "$item 是其他类型"
fi
done
while循环
#!/bin/bash
read -p "请输入一个正整数: " n
while [ $n -gt 0 ]
do
echo "当前数字是: $n"
n=$((n - 1))
done
echo "循环结束!"
函数
函数定义
function 函数名(){
函数体
}
函数的调用与返回
函数的调用和平时调用命令一样
写一个test.sh脚本,并定义文件内容如下:
#!/bin/bash
function max(){
if [ $1 -gt $2 ];then
echo $1
else
echo $2
fi
}
max_val=$(max $@)
echo "max num is $max_val"
然后在终端命令行输入
./test.sh 12 45
执行结果如下所示
文件导入
定义一个max.sh文件
#!/bin/bash
function Max(){
if [ $1 -gt $2 ];then
echo $1
else
echo $2
fi
}
然后再定义一个main.sh文件
#!/bin/bash
#导入max.sh文件
source max.sh
read -p "num1=" num1
read -p "num2=" num2
#使用max.sh文件中的Max函数
max_val=$(Max $num1 $num2)
echo "max_val is $max_val"
终端命令行执行
参考
shell脚本语言(超全超详细) - 知乎