shell简介
shell 脚本的优势在于处理偏操作系统底层的业务,例如,linux内容的很多应用都是使用shell脚本开发的,因为有1000多个linux系统命令为他作支撑,特别是linux正则表达式及三剑客grep、awk、sed等命令。
shell的基本格式
command [选项][参数]
变量
variable=value
variable='value'
variable="value"
- 赋值号=周围不能有空格
- 变量由字母、数字、下划线组成
- 必须以字母或下划线开头
- 不能使用shell里面的关键字
echo $variable
echo ${variable}
variable="java"
echo "I am good at ${variable}Script"
echo 'I am good at ${variable}Script'
变量名外面的{} 是可选的,增加为了识别边界,建议都增加
单引号不会解析字符串中的参数,按字符串输入,双引号会解析
- 将命令的结果赋值给变量
variable=`command`
variable=$(command) ## 推荐使用该方式
log=$(cat log.txt)
echo "$log"
command 可以只是一个命令,也可以多个命令;分隔。
$()支持嵌套,反引号不行。
$() 仅在 Bash Shell 中有效,而反引号可在多种 Shell 中使用
注意:如果被替换的命令输出内容包括多行(有换行符),或者连续空格需要双引号包围,否则系统默认空白符填充,多个空格压缩成一个。
- 只读变量
readonly 命令定义只读变量,只读变量的值不能改变。
readonly myUrl
- 删除变量
unset命令删除变量,变量不能被再次使用,不能删除只读变量
unset variable
命令行参数
运行shell脚本文件,可以传递参数,以1第一个参数。
调用函数时也可以传递参数,shell与其他语言不同,定义时不能指定参数,内部可以通过n形式接受的参数在shell中成为位置参数,除此还有*、?、$$几个特殊参数。
#!/bin/bash
#定义函数
function func(){
echo "language:${1}"
echo "URl:$2"
}
func C++ http://www.baidu.com
如果参数超过10个需要增加{}识别边界
变量 | 说明 |
---|---|
$0 | 当前脚本的文件名 |
$n (n>0) | 传递给脚本或函数的参数,n数字表示第几个采纳数 |
$# | 传递给脚本或函数的参数个数 |
$* | 传递给脚本或函数的所有参数 |
$@ | 传递给脚本或函数的所有参数。当被双引号包括是意义不同 |
$? | 上一个命令的退出状态,或函数的返回值 |
$$ | 当前shell的进程ID |
- 给脚本文件传递参数
编写test.sh
#!/bin/bash
echo "process ID:$$"
echo "File Name:$0"
echo "First Parameter:$1"
echo "Second Parameter:$2"
echo "All parameters 1:$@"
echo "All parameters 2:$*"
echo "Total :$#"
运行test.sh
./test.sh shell linux
$?是一个特殊变量,用来获取上一个命令的退出状态,就是上一个命令的执行结果,退出状态是一个数字,一般情况下成功返回0,失败返回1。不过也有一些命令返回其它值,标识不同类型的错误。
#!/bin/bash
if ["$1" ==100]
then
exit 0
else
exit 1
fi
- 获取函数的返回值
#!/bin/bash
#得到两个数相加的和
function add(){
return `expr $1+$2`
}
add 23 50
echo $?
严格来说,shell函数的return标识返回状态,而不是返回值,shell没有专门的返回值关键字。
字符串
字符串是一系列字符的组合,用单引号、双引号或不用引号包围。
三种形式的区别
单引号'' :
- 任何字符都会原样输出,在其中使用便利是无效的。
- 字符串不能出现单引号,及时转义也不行。
双引号"": - 如果其中包含变量会被解析
- 字符串中可以出现双引号,需要转义
不被引号包围: - 出现变量也会被解析,和双引号类似
- 字符串不能出现空格,否则空格右边的字符串会被当做其它变量或命令解析。
例,
n=74
str1=$n str2="shell \"script\" $n"
str3='C语言 $n'
=号两边不能有空格
- 获取字符串长度
str3="111"
echo ${#str3}
在shell中不需要任何运算符,将两个字符串并排放在一起就能实现拼接。
name="shell"
url="wwww"
str1=$name$url
echo str1
字符串截取通常两种方式:指定位置,指定字符
- 指定位置截取
两个参数:起始位置和截取长度
## 从左向右 ${str:start:length} length可以省略标识末尾,start从0开始
url="1234"
echo ${url:2:3}
echo ${url:1}
## 从右向左 ${str:0-start:length} ,从1开始,截取方向都是从左向右
echo ${url: 0-2:3}
- 指定字符串
这种截取无法指定字符串长度,智能从指定字符截取到字符串末尾。
#使用#号截取右边字符,*是通配符一种,*char忽略左边字符串直,#第一个,##最后一个开始到遇到char
${str#*char}
${str##*char}
## 使用%截取左边的字符串 ${str%char*},%与#类似
a="111113e33@44@"
echo ${a%@*}
echo ${a%%@*}
汇总:
格式 | 说明 |
---|---|
${str:start:length} | 从字符串左边start开始,向右截取length字符 |
${str:star} | 从字符串左边start开始,截取到结尾 |
${str:0-start:length} | 从字符串右边start开始,向右截取length字符 |
${str:0-star} | 从字符串右边start开始,截取到结尾 |
${str#*char} | 从字符串左边第一次出现char开始,截取右边字符 |
${str##*char} | 从字符串左边最后一次出现char开始,截取右边字符 |
${str%char*} | 从字符串右边第一次出现char开始,截取左边字符 |
${str%%char*} | 从字符串右边最后一次出现char开始,截取左边字符 |
数组
shell 并没有显示数组的大小,理论上可以存放无限量的数据。获取元素使用下标[],下标自然数。遗憾常用bash shell 只支持一维数组。
- 数组的定义
使用()表示数组元素,数组之间用空格分隔,弱类型,不要求元素类型相同,长度不固定通过赋值扩展
array_name=(ele1 ele2 ele3)
例如
arr=(20 50 "test")
arr[3]=88 #长度变成了4
arr=([3]=77 [2]="test2") # 长度变成2,只有 2 3 有值
- 获取数组元素
array_name 数组名,index是下标 0开始
使用@或*可以获取数组所有元素
${array_name[index]}
例如:
#!/bin/bash
nums=(29 100 13 91)
echo ${nums[@]}
nums[10]=66
echo ${nums[4]}
- 获取数组长度
通过#获取长度
${#array_name[*]} 获取数组元素个数
${#array_name[index]} # 获取某个元素的字符串长度
- 数组合并
先利用@或* 将数组扩展成列表,然后再合并到一起
- 删除数组元素
unset array_name[index] #删除index元素
unset array_name # 删除数组
数学计算
shell不能直接进行算数运算,需要数学计算命令
运算操作符/运算命名了 | 说明 |
---|---|
(()) | 用于整数运算,效率很高,推荐使用 |
let | 用于整数运算,和(())类似 |
$[] | 用于整数运算,没有(())灵活 |
expr | 整数运算,可以处理字符串,不推荐 |
bc | linux下的计算器程序,可以处理整数和小数 |
declare -i | 将变量定义成整数,数学运算时就不需要当做字符串了,功能有限,不支持逻辑运算 |
- Shell (())的用法
可以多个,逗号分隔,最后一个计算值作为结果
((表达式))
# 获取表达式值,$
$((表达式))
例,
((a=1+2**3-4%3))
b=$((1+2**3-4%3))
- let 用法
# let '表达式' 或let "表达式"
let 表达式
# 多个表达式,空格分隔
let c=1+3
if语句
本质上,if检测的是命令的退出状态。
- if基本语法
if condition
then
statement(s)
fi
# 写到一行
if condition; then
statement(s)
fi
- if elif else 语句
if condition
then
statement1
elif condition2
then
statement2
else
statement3
fi
例,
read age
read iq
if (($age>18 && &iq < 60))
then
echo "不及格"
elif (($age==18 && &iq == 60))
then
echo "勉强"
else
echo "OK"
fi
test
Shell 内建命令,用来检测某一个条件是否成立。通常和if配合使用。
可进行数值、字符串和文件三方面检测。
test expression
[ expression ]
- 文件类型检测
选项 | 说明 |
---|---|
-b filename | 判断文件是否存在,并且是否为块设备文件 |
-c filename | 判断文件是否存在,并且是否为字符设备文件 |
-d filename | 判断文件是否存在,并且是否为目录 |
-e filename | 判断文件是否存在 |
-f filename | 判断文件是否存在,并且为普通文件 |
-L filename | 判断文件是否存在,并且为符号链接文件 |
-p filename | 判断文件是否存在,并且为管道文件 |
-s filename | 判断文件是否存在,并且是否为非空 |
-S filename | 判断文件是否存在,兵器是否为套接字文件 |
- 文件权限检测
选项 | 说明 |
---|---|
-r | 判断文件是否存在,并拥有读权限 |
-w | 判断文档是否存在,并拥有写权限 |
-x | 判断文件是否存在,并拥有执行权限 |
-u | 判断文件是否存在,并拥有SUID权限 |
-g | 判断文件是否存在,并是否拥有SGID权限 |
-k | 判断文件是否存在,并是否拥有SBIT权限 |
- 文件比较
选项 | 说明 |
---|---|
filename1 -nt filename2 | 判断filename1的修改时间是否比filename2 新 |
-ot | ...旧 |
-ef | 判断文件的inode是否一致,可以理解是否同一个文件。 |
#!/bin/bash
read filename
read url
if test -w $filename && test -n $url
then
echo $url > $filename
echo "写入成功"
else
echo "写入失败"
fi
- 数值比较相关
选项 | 说明 |
---|---|
-eq | 是否相等 |
-ne | 不能 |
-gt | 大于 |
-lt | 小于 |
-ge | 大于等于 |
-le | 小于等于 |
- 字符串判断
不支持>= 和 <= 运算符
选项 | 说明 |
---|---|
-z str | 是否为空 |
-n str | 是否非空 |
str1=str2 str1==str2 | 是否相等 |
str1!=str2 | 不相等 |
str1>str2 | 是否大于,防止>被误认为重定向运算符 |
str1小于 |
|
- 逻辑运算相关
选项 | 说明 |
---|---|
-a | 与 |
-o | 或 |
! | 非 |
if [ -z "$str1" -o -z "$str2" ]
then
echo "字符串不能为空"
exit 0
fi
- test中使用便利建议用双引号包围起来
test 和[] 都是命令,本质上对应一个程序或者一个函数,可都看成函数,命令后的选项和参数最终作为实参传递给函数,使用"" 可以避免很多空值导致的奇葩问题
[[ ]]
shell内置关键字,和test命令相似,检测某个条件是否成立。
#注意两侧有空格
[[ expressioin ]]
- 不需要把变量名用双引号""包围,即便是空值也不会出错
- 不需要、也不能对> <进行转义
- 支持逻辑运算符
[[ -z $str1 || -z $str2 ]]
-支持正则表达式
[[ str =~ regex ]]
case in
当分支条件多,判断条件简单,使用case in 更方便
case expression in
pattern1)
statement1
;;
pattern2)
statement2
;;
...
*)
statementn
esac
- expression 既可以是一个变量、数字、字符串、数学表达式或命令执行结果,只要能得到expression的值就可以。
- pattern 可以是一个数字、字符串、甚至一个简单表达式。
正则表达式:
格式 | 说明 |
---|---|
* | 表示任意字符串 |
[abc] | 标识 a、b、c三者任意一个 |
[m-n] | 从m到n的任意字符 |
| | 标识多重选择,类似或,例如abd|cdr 标识abd 或cdr |
例,
#!/bin/bash
printf "input a character"
read -n 1 char
case $char in
[a-zA-Z])
printf "\nletter\n"
;;
[0-9])
printf "\nDigit\n"
;;
*)
printf "\nerror\n"
esac
while
condition 的用户和if else一致,可以使用 test、[] 、 [[]]、(())
while condition
do
statements
done
例,
#!/bin/bash
sum=0
echo "请输入你要计算的数据,按ctrl+D结束读取"
while read n
do
((sum+=n))
done
echo "The sum is :$sum"
until 循环
与while循环恰好相反,当条件不满足执行。
until condition
do
statements
done
for
Shell for 循环有两种使用形式。
- C 语言风格的for循环
for((exp1;exp2;exp3))
do
statements
done
- Python 风格的for in循环
value_list 部分可以省略,效果相当$@
for variable in value_list
do
statements
done
- 对for in 语法中value_list说明
- 直接给出具体指,比如 1 2 3 4 5
- 给出一个取值范围 {start..end}
3.使用命令的执行结果
使用反引号或者$()都可以取得命令执行结果
例,
#!/bin/bash
sum=0
for n in $(seq 2 2 100)
do
((sum+=n))
done
echo $sum
for filename in $(ls *.sh)
do
echo $filename
done
4.使用Shell通配符
#!/bin/bash
for filename in *.sh
do
echo $filename
done
5.使用特殊变量
shell中有多个特殊的变量,例如*、?等
#!/bin/bash
functioin func(){
for str in $@
do
echo $str
done
}
func C++ java Python C#
select in 循环详解
select in 循环用来增强交互性,可以显示出带编号的菜单,用编号选择菜单。
select variable in value_list
do
statements
done
例如,
#!/bin/bash
echo "what is your favourite OS?"
select name in "Linux" "Windows" "Mac OS" "UNIX"
do
echo $name
done
echo "you have selected $name"
?用来提示用户输入菜单编号;ctrl+D 组合键结束循环。
注意: select 是无线循环,break 或者ctrl+D 退出循环
break 和continue
使用while、until、for、select 循环是,如果想结束循环使用关键字
shell 中break 和continue 可以跳出多层循环
- break 关键字
n 表示跳出循环的层数,如果省略n,表示跳出当前循环
break n
- continue 关键字
n 表示循环的层数。
continue n
例,
#!/bin/bash
sum=0
while read n;
do
if((n<1 || n>100)); then
continue
fi
((sum+=n))
done
echo "sum=$sum"
shell 函数详解
shell本质是一段可以重复使用的脚本代码。
函数的定义语法格式如下:
function name(){
statements
[return value]
}
- 简化写法
建议使用标准写法
name(){
statements
[return value]
}
如果写了function关键字,也可以省略函数名后面的小括号:
function name{
statements
[return value]
}
- 函数调用
和其它编程语言不同的是,shell函数在定义时不能指定参数,但是调用时却可以带参数
也不限制定义和调用顺序
name param1 param2 param3
实例,
#!/bin/bash
function url(){
echo "hello"
}
url
function getsum(){
local sum=0
for n in $@
do
((sum+=n))
done
return $sum
}
getsum 10 20 44
echo $?