shell笔记
一.基础语法
1.shell用途:用于运维,含义是shell是图形界面和命令行的连接桥梁,Shell 是将内核、程序和用户连接起来。无需编译直接运行源码,因为它是解释性语言。
2.shell位置: /etc/shells
文件中
3.进入shell的两种方式:命令模式和终端模式。
4.提示符:普通用户($)和超级用户(#)。
5.shell的格式是.sh。
6.查看shell进程方法:echo $$
7.当前进程中运行 Shell 脚本的方法:(…/ xx.sh)
8.shell的变量
①变量3种类型:x=2,x='2’和x=“2”。注意=两边不能有空格。
②变量的使用:$+变量名。
③单引号和双引号的区别:单引号用于不解析变量和命令的场景,是什么就输出什么,双引号用于解析变量和命令的场景。如下:
website1='C语言中文网:${url}'
website2="C语言中文网:${url}"
结果是:
C语言中文网:${url} C语言中文网:http://c.biancheng.net
④命令的结果赋值给变量的语法:
$(命令语句)
eg: log=$(cat log.txt)
⑤只读变量:使用readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变。
⑥删除变量:unset+变量名,不过只读变量不可删除。
9.shell变量三种作用域:
①全局变量:在当前整个shell中有效。
②局部变量:用于函数中。
③环境变量:通过export命令就可以作用于所有子shell中。就是传子不传父。eg:export+变量名
注意①:创建子shell方法,就是通过bash命令即可。
注意②:退出子shell的方法:用exit。
10.特殊变量:
变量 | 含义 |
---|---|
$0 | 当前脚本的文件名。 |
$n(n≥1) | 传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是 $1,第二个参数是 $2。 |
$# | 传递给脚本或函数的参数个数。 |
$* | 传递给脚本或函数的所有参数。 |
$@ | 传递给脚本或函数的所有参数。当被双引号" " 包含时,$@ 与 $* 稍有不同,我们将在《Shell
∗
和
*和
∗和@的区别》一节中详细讲解。 |
$? | 上个命令的退出状态,或函数的返回值,我们将在《Shell $?》一节中详细讲解。 |
$$ | 当前 Shell 进程 ID。对于 Shell 脚本,就是这些脚本所在的进程 ID。 |
11.字符串
①获取字符串长度的方法:echo ${#字符串名}
②字符串拼接:用 符 号 连 接 , 其 中 无 引 号 时 符号连接,其中无引号时 符号连接,其中无引号时前后不可以有空格,加引号时$前后可以有空格。
③字符串截取方法:echo ${字符串名: 开始位置:结束位置}。
echo ${url: 2: 9}
④字符串指定字符截取的语法是:
截取右边的语法:
${字符串#*字符}和 ${字符串#字符}
截取左边语法: ${字符串%字符*}
12.shell数组:
①数组定义,()表示数组,空格来隔开数组元素。
②获取数组元素: ${数组名[下标]}
③遍历数组方法:
${数组名[*]}
${数组名[@]}
④获取数组长度:
${#数组名[@]}$和{#数组名[*]}
⑤添加元素:数组名[下标]=值
⑥删除数组元素语法:unset 数组名[下标]
⑦数组拼接:
新数组名=(${数组1[@]}${数组2[@]})
新数组名=(${数组1[*]}${数组2[*]})
⑧关联数组
获取所有元素的下标和值
使用下面的形式可以获得关联数组的所有元素值:
${array_name[@]}
${array_name[*]}
使用下面的形式可以获取关联数组的所有下标值:
${!array_name[@]}
${!array_name[*]}
获取关联数组长度
使用下面的形式可以获得关联数组的长度:
${#array_name[*]}
${#array_name[@]}
13.Shell内置命令:通过type来判断,如: type cd
14.命令创制别名方法: alias+命令=‘别名’,删除别名用unalias+别名
15.echo输出命令:默认换行,不换行用echo -h或者echo -e “xxxxx ,\c”
16.read输入命令语法:read -p “请输入?” 默认是换行输入的,不换行输入用read -n -p “请输入?”
整体语法是: read [-options] [variables]
shell read命令支持选项
选项 | 说明 |
---|---|
-a array | 把读取的数据赋值给数组 array,从下标 0 开始。 |
-d delimiter | 用字符串 delimiter 指定读取结束的位置,而不是一个换行符(读取到的数据不包括 delimiter)。 |
-e | 在获取用户输入的时候,对功能键进行编码转换,不会直接显式功能键对应的字符。 |
-n num | 读取 num 个字符,而不是整行字符。 |
-p prompt | 显示提示信息,提示内容为 prompt。 |
-r | 原样读取(Raw mode),不把反斜杠字符解释为转义字符。 |
-s | 静默模式(Silent mode),不会在屏幕上显示输入的字符。当输入密码和其它确认信息的时候,这是很有必要的。 |
-t seconds | 设置超时时间,单位为秒。如果用户没有在指定时间内输入完成,那么 read 将会返回一个非 0 的退出状态,表示读取失败。 |
-u fd | 使用文件描述符 fd 作为输入源,而不是标准输入,类似于重定向。 |
17.exit退出进程命令:eg exit 8
20.数学计算:
算术运算符
算术运算符 | 说明/含义 |
---|---|
+、- | 加法(或正号)、减法(或负号) |
*、/、% | 乘法、除法、取余(取模) |
** | 幂运算 |
++、– | 自增和自减,可以放在变量的前面也可以放在变量的后面 |
!、&&、|| | 逻辑非(取反)、逻辑与(and)、逻辑或(or) |
<、<=、>、>= | 比较符号(小于、小于等于、大于、大于等于) |
==、!=、= | 比较符号(相等、不相等;对于字符串,= 也可以表示相当于) |
<<、>> | 向左移位、向右移位 |
~、|、 &、^ | 按位取反、按位或、按位与、按位异或 |
=、+=、-=、*=、/=、%= | 赋值运算符,例如 a+=1 相当于 a=a+1,a-=1 相当于 a=a-1 |
shell常用6种数学计算公式
运算操作符/运算命令 | 说明 |
---|---|
(( )) | 用于整数运算,效率很高,推荐使用。如:((a=1+2**3-4%3)) |
let | 用于整数运算,和 (()) 类似。如:let a+=6 c=a+b |
[$] | 用于整数运算,不如 (()) 灵活。如:echo $[(3+4)*5] |
expr | 可用于整数运算,也可以处理字符串。比较麻烦,需要注意各种细节,不推荐使用。看你心烦 |
bc | Linux下的一个计算器程序,可以处理整数和小数。Shell 本身只支持整数运算,想计算小数就得使用 bc 这个外部的计算器。如:echo “scale=4;3*8/7;last**5” |
declare -i | 将变量定义为整数,然后再进行数学运算时就不会被当做字符串了。功能有限,仅支持最基本的数学运算(加减乘除和取余),不支持逻辑运算、自增自减等,所以在实际开发中很少使用。如:声明三个变量:declare -i m n ret |
注意:加减乘除用[]来进行计算,如echo $[32+/-/*///%/** 4]或者用let来计算,let y=2**3。
21.语句
①if语句语法===》一个分支
if 条件
then
语句
fi
如
read a
read b
if (( $a == $b ))
then
echo "a和b相等"
fi
②if else 语句语法===》两个分支
if 条件
then
语句1
else
语句2
fi
③if elif else 语句====》多个分支,注意 注意,if 和 elif 后边都得跟着 then
if 条件1
then
语句1
elif 条件2
then
语句2
elif 条件3
then
语句3
……
else
语句n
fi
④case in语句===用于分支比较多;
语法:
case expression in
pattern1)
statement1
;;
pattern2)
statement2
;;
pattern3)
statement3
;;
……
*)
statementn
esac
eg:
printf "Input integer number: "
read num
case $num in
1)
echo "Monday"
;;
2)
echo "Tuesday"
;;
3)
echo "Wednesday"
;;
4)
echo "Thursday"
;;
5)
echo "Friday"
;;
6)
echo "Saturday"
;;
7)
echo "Sunday"
;;
*)
echo "error"
esac
⑤while语句:用于条件成立才循环
语法:
while 条件
do
语句
done
eg:
i=1
sum=0
while ((i <= 100))
do
((sum += i))
((i++))
done
echo "The sum is: $sum"
⑥until语句:用于条件不成立才循环
语法:
until 条件
do
语句
done
eg:
i=1
sum=0
until ((i > 100))
do
((sum += i))
((i++))
done
echo "The sum is: $sum"
⑦for语句:
语法
for((exp1; exp2; exp3))
do
语句
done
eg:
sum=0
for ((i=1; i<=100; i++))
do
((sum += i))
done
echo "The sum is: $sum"
⑧select in语句:用来增强交互性,用于输入不同编号就可以选择不同菜单。
语法
select variable in value_list
do
语句
done
eg:
echo "What is your favourite OS?"
select name in "Linux" "Windows" "Mac OS" "UNIX" "Android"
do
echo $name
done
echo "You have selected $name"
结束条件是: Ctrl+D 组合键
⑨break和continue语句
eg1:
i=0
while ((++i)); do #外层循环
if((i>4)); then
break #跳出外层循环
fi
j=0;
while ((++j)); do #内层循环
if((j>4)); then
break #跳出内层循环
fi
printf "%-4d" $((i*j))
done
printf "\n"
done
eg2:
sum=0
while read n; do
if((n<1 || n>100)); then
continue
fi
((sum+=n))
done
echo "sum=$sum"
eg3:
for((i=1; i<=5; i++)); do
for((j=1; j<=5; j++)); do
if((i*j==12)); then
continue 2
fi
printf "%d*%d=%-4d" $i $j $((i*j))
done
printf "\n"
done
break 和 continue 的区别
break 用来结束所有循环,循环语句不再有执行的机会;continue 用来结束本次循环,直接跳到下一次循环,如果循环条件成立,还会继续循环
22.shell退出状态:
如
read filename
read url
if test -w $filename && test -n $url
then
echo $url > $filename
echo "写入成功"
else
echo "写入失败"
fi
23.test命令:作用检测某个条件是否成立。test 通常和 if 语句一起使用。如下:
read age
if test $age -le 2; then
echo "婴儿"
elif test $age -ge 3 && test $age -le 8; then
echo "幼儿"
elif [ $age -ge 9 ] && [ $age -le 17 ]; then
echo "少年"
elif [ $age -ge 18 ] && [ $age -le 25 ]; then
echo "成年"
elif test $age -ge 26 && test $age -le 40; then
echo "青年"
elif test $age -ge 41 && [ $age -le 60 ]; then
echo "中年"
else
echo "老年"
fi
文件类型判断 | |
---|---|
选 项 | 作 用 |
-b filename | 判断文件是否存在,并且是否为块设备文件。 |
-c filename | 判断文件是否存在,并且是否为字符设备文件。 |
-d filename | 判断文件是否存在,并且是否为目录文件。 |
-e filename | 判断文件是否存在。 |
-f filename | 判断文件是否存在,井且是否为普通文件。 |
-L filename | 判断文件是否存在,并且是否为符号链接文件。 |
-p filename | 判断文件是否存在,并且是否为管道文件。 |
-s filename | 判断文件是否存在,并且是否为非空。 |
-S filename | 判断该文件是否存在,并且是否为套接字文件。 |
文件权限判断 | |
选 项 | 作 用 |
-r filename | 判断文件是否存在,并且是否拥有读权限。 |
-w filename | 判断文件是否存在,并且是否拥有写权限。 |
-x filename | 判断文件是否存在,并且是否拥有执行权限。 |
-u filename | 判断文件是否存在,并且是否拥有 SUID 权限。 |
-g filename | 判断文件是否存在,并且是否拥有 SGID 权限。 |
-k filename | 判断该文件是否存在,并且是否拥有 SBIT 权限。 |
文件比较 | |
选 项 | 作 用 |
filename1 -nt filename2 | 判断 filename1 的修改时间是否比 filename2 的新。 |
filename -ot filename2 | 判断 filename1 的修改时间是否比 filename2 的旧。 |
filename1 -ef filename2 | 判断 filename1 是否和 filename2 的 inode 号一致,可以理解为两个文件是否为同一个文件。这个判断用于判断硬链接是很好的方法 |
Shell test 文件检测举例:
复制纯文本复制
#!/bin/bash read filenameread url if test -w $filename && test -n $urlthen echo $url > $filename echo "写入成功"else echo "写入失败"fi
#!/bin/bash
read filename
read url
if test -w $filename && test -n $url
then
echo $url > $filename
echo "写入成功"
else
echo "写入失败"
fi
2) 与数值比较相关的 test 选项
选 项 | 作 用 |
---|---|
num1 -eq num2 | 判断 num1 是否和 num2 相等。 == |
num1 -ne num2 | 判断 num1 是否和 num2 不相等。!= |
num1 -gt num2 | 判断 num1 是否大于 num2 。 > |
num1 -lt num2 | 判断 num1 是否小于 num2。< |
num1 -ge num2 | 判断 num1 是否大于等于 num2。>= |
num1 -le num2 | 判断 num1 是否小于等于 num2。<= |
与字符串判断相关 test 选项
选 项 | 作 用 |
---|---|
-z str | 判断字符串 str 是否为空。 |
-n str | 判断宇符串 str 是否为非空。 |
str1 = str2 str1 == str2 | = 和== 是等价的,都用来判断 str1 是否和 str2 相等。 |
str1 != str2 | 判断 str1 是否和 str2 不相等。 |
str1 > str2 | 判断 str1 是否大于 str2。\> 是> 的转义字符,这样写是为了防止> 被误认为成重定向运算符。 |
str1 < str2 | 判断 str1 是否小于 str2。同样,\< 也是转义字符。 |
与逻辑运算相关的 test 选项
expression1 -a expression | 逻辑与,表达式 expression1 和 expression2 都成立,最终的结果才是成立的。 |
---|---|
expression1 -o expression2 | 逻辑或,表达式 expression1 和 expression2 有一个成立,最终的结果就成立。 |
!expression | 逻辑非,对 expression 进行取反。 |
注意,test 只能用来比较整数,小数相关的比较还得依赖 bc 命令。
总结:
test 命令比较奇葩,>、<、== 只能用来比较字符串,不能用来比较数字,比较数字需要使用 -eq、-gt 等选项;不管是比较字符串还是数字,test 都不支持 >= 和 <=。
22.Shell [[]]详解:检测某个条件是否成立,可以完全代替test命令。
eg1:
read str1
read str2
if [[ -z $str1 ]] || [[ -z $str2 ]] #不需要对变量名加双引号
then
echo "字符串不能为空"
elif [[ $str1 < $str2 ]] #不需要也不能对 < 进行转义
then
echo "str1 < str2"
else
echo "str1 >= str2"
fi
eg2:正则表达式
read tel
if [[ $tel =~ ^1[0-9]{10}$ ]]
then
echo "你输入的是手机号码"
else
echo "你输入的不是手机号码"
fi
23.函数:
①无参方法:
定义如下:
function 方法名() {
语句
[return 返回值]
}
调用:函数名
如:
#函数定义
function url(){
echo "http://c.biancheng.net/shell/"
}
#函数调用
url
②有参方法
eg1:使用 $n 来接收函数参数。
#定义函数
function show(){
echo "Tutorial: $1"
echo "URL: $2"
echo "Author: "$3
echo "Total $# parameters"
}
#调用函数
show C# http://c.biancheng.net/csharp/ Tom
运行结果:
Tutorial: C#
URL: http://c.biancheng.net/csharp/
Author: Tom
Total 3 parameters
eg2: 使用 $@ 来遍历函数参数来计算所有参数的和
function getsum(){
local sum=0
for n in $@
do
((sum+=n))
done
echo $sum
return 0
}
echo $(getsum 10 20 55 15)
结果100
③函数返回值:用return $?表示
function getsum(){
local sum=0 #局部变量
for((i=$1; i<=$2; i++)); do
((sum+=i))
done
echo $sum
return $?
}
read m
read n
echo "The sum is "$(getsum $m $n)
结果是:1 100 5050