(注意:linux中要写shell脚本,必须是.sh的文件,eg: touch tesh.sh ;vim test.sh ; sh test.sh)
Shell是一个命令行表达式,能接受应用程序或用户的命令,然后调用os内核。
Shell脚本固定以#!/bin/bash开头(指定为bash解析器)
bash和sh的关系:sh是bash的一个软链接
入门篇
- 定义变量
eg: name="zhangsan"
注:变量名和等号之间不能有空格。同时,变量名命名要遵循以下规则:
1.命名只能用英文字母、数字、下划线,首字符不能以数字开头
2.变量名之间不能有空格(有空格的话linux会把它当成一个命令),可以有_
3.不能用标点符号
4.不能用bash里的关键字(可用help查看关键字)
- 声明静态变量(当虚拟机重启后就没了)
readonly 变量名=值
- 将变量提升为全局变量
export 变量名
}
- $n($0是脚本名 $1-.....是输入的参数1-....)
- $#(获取所有输入参数的个数,常用于循环)
- $*(代表命令行中所有的参数)
- $@(也代表命令行中所有的参数,不过$@把每个参数区别对待)
- $?(最后一次命令的返回状态,0代表正确执行,非0代表不正确执行)
- 使用变量
echo $ name
echo ${name} 花括号可加,可不加
- 删除变量
unset name
注意:echo是个命令,所以需要有空格,只有赋值变量才没有空格
shell字符串
- 字符串可以用单引号,也可以用双引号(但是双引号可以引用变量,单引号不行)
str="hello world!"
str='hello world!'
- 获取字符串长度
echo ${#str}
- 提取字符串
echo ${name:1} 它的意思是选取字符串从第1个到最后一个
echo ${name:0:3}它的意思是选取字符串从0到2
echo ${name:0:100}如果没有100个字符怎么办?最后它会选取到最后一个字符
shell数组
- shell只支持一维数组,用括号表示,元素用空格符号分隔开
array=(val1 val2 val3)
- 通过下标定义数组
array[0]=val1
array[1]=val2
- 读取数组元素
echo ${array[0]}
- 获取全部元素
echo ${array[*]}
- 获取数组长度
echo ${#array[*]}
运算符
1.算术运算符
原生bash不支持简单的数学运算,但可以通过其他命令来实现
- 两数相加、减、除(这里用的反引号`,而不是单引号')
val=`expr 2 + 2`
val=`expr 2 - 2`
val=`expr 2 / 2`
也可以直接算val=$[2+2]
(注意:表达式和运算符之间要有空格,比如2+2是不对的,要写成 2 + 2 ,完整的表达式要被``包含)
- 两数相乘(要用到转义符号,* → \* )
val=`expr 2 \* 2`
- 取余
val=`$a % $b` (这里a、b是变量)
- 赋值
a=$b (把b的值赋给a)
- 比较相等
[ $a == $b ] (相同返回true,不同返回false)
- 比较不等
[ $a != $b ](不同返回true,相同返回false)
注意:条件表达式要放在方括号之间,而且必须有空格,
比如:[$a == $b]就是错的,[ $a == $b ]才是对的
2.关系运算符
- 运算符-eq(equal) :检测两数是否相等,相等返回true,不同返回false
eg: [ $a -eq $b ]
- 运算符-ne(not equal):检测两数是否不等,不等返回true,相等返回false
eg:[ $a -ne $b ]
- 运算符-gt(greater than):检测a>b?true:false
eg:[ $a -gt $b ]
- 运算符-lt(less than):检测a<b?true:false
eg:[ $a -lt $b ]
- 运算符-ge(greater equal):检测a>=b?true:false
eg:[ $a -ge $b ]
- 运算符-le(less equal):检测a<=b?true:false
eg:[ $a -le $b ]
3.布尔运算符
- 非运算!
eg:[ ! false ]返回true
- 或运算-o
eg:[ $ a -lt 20 -o $b -gt 100 ]
- 与运算-a
eg:[ $ a -lt 20 -a $b -gt 100 ]
4.逻辑运算符
- &&
eg:[ $a -lt 100 && $b -gt 100]
- ||
eg:[ $a -lt 100 || $b -gt 100]
5.字符串运算符
- =:检测两字符串是否相等,相等返回true,不相等返回false
eg:[ $a = $b ]
- !=:检测两字符串是否不等,不等返回true,相等返回false
eg:[ $a != $b ]
- -z:检测字符串长度是否为0,为0返回true,不为0返回false
eg:[ -z $a ]
- -n:检测字符串长度是否不为0,不为0返回true,为0返回false
eg:[-n $a ]
- str:检测字符串是否不为空,不为空返回true
eg:[ $a ]
条件控制语句
语法:
if condition1
then
command1
elif condition2
then
command2
else
commandN
fi
for循环
第一种:
for ((初始值;循环控制条件;变量变化))
do
command1
.......
done
第二种:
for val in item1 item2 item3 ... itemN
do
command1
....
commandN
done
while循环
语法:
while comndition
do
command
done
(这里可能会报错,可能是let的原因,因为/bin/sh指向dash而不是bash,dash不支持let命令
所以,解决办法如下:输入sudo dpkg-reconfigure dash
输入密码
出现个设定dash,选择“否”
)
标准输入与输出
把输出写入文件: ls -l > ls.txt(删除,覆盖效果)
把输出追加到文件:ls -l >> ls.txt(保留,追加效果)
标准错误
- 通常情况下,标准和错误信息的输出混合在一起
- 如果我想要将标准和错误信息混合输出到文件,可以用2>&1
eg:python test.py >r.txt 2>&1
- 使用bash shell时,可以用2<把标准错误流重定向到文件
案例:
重定向正确的输出:head -l /etc/* > result.log
重定向标准错误:head -l /etc/* 2 > error.log
分别重定向标准输出和标准错误:head -l /etc/* >result.log 2>error.log(常用)
Read读取控制台的输入
选项:
read -p:指定读取值时的提示符
read -t:指定读取值时等待时间(秒)
参数:变量
函数
系统函数
1.basename [ string / pathname ] [ suffix ]
(basename会删掉所有的前缀,包括最后一个‘/’字符,然后将字符串显示出来)
(如果后缀suffix被指定了,basename会将string/pathname中的suffix去掉)
eg:截取/home/zyy/test.txt路径的文件名称
basename /home/zyy/test.txt
basename /home/zyy/test.txt .txt
2.dirname 文件绝对路径
(从给定的绝对路径中去除文件名(非目录部分),然后返回剩下的路径(目录部分))
eg:获取test.sh的绝对路径
dirname /home/zyy/test.sh
自定义函数
1.基本语法
[ function ] fun_name[()]
{
具体内容
[ return $? ]
}
eg:计算两个输入参数的和
function sum()
{
s=0;
s=$[$1 + $2]
echo $s
}
read -p "输入第一个参数:" p1
read -p "输入第二个参数:" p2
sum $p1 $p2
Shell工具
cut
cut负责在文件中剪切数据,从文件的每行剪切字节、字符、字段,并将这些字节、字符、字段输出
1.基本用法
cut [选项参数] filename
选项参数:-f :列号,提取第几列
-d:分隔符,按照指定分隔符分割列
eg: 切割cut.txt第一列
eg:切割cut.txt第二、三列
eg:在cut文件中切割出“hao”
eg:选取系统PATH变量,第二个:开始后的路径(3-代表第三列及之后所有的)
sed
sed是一种流编辑器,一次处理一行的内容。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”。然后用sed命令处理缓冲区的内容,处理完成后把缓冲区的内容送往屏幕,接着处理下一行,如此反复。文件内容不会发生改变
1.基本用法
sed [选项参数] 'command' filename
选项参数:-e :多个命令时候加-e
a:新增,a后面能拼接字符串,在下一行出现
d:删除
s:查找并替换
eg:把“hello”这个词插入到sed.txt第二行下(a是插入,2a就是在第二行插入),打印
注意,文件内容不会发生变化
eg:删除sed.txt所有包含hello的行
eg:将sed.txt中的hello替换成world(加g是全局替换,不加只替换第一个)
eg:既把“hello”这个词插入到sed.txt第二行下,又将sed.txt中的hello替换成world
awk
和cut很像,只是处理形式不一样。
把文件逐行读入,以空格为默认分隔符将每行切片,切开的部分再进行分析处理。
1.基本用法
awk [选项参数] ‘pattern1 {action1} pattern2 {action2}...' filename
pattern:表示AWK在数据中查找的内容,就是匹配模式。
action:找到匹配内容时所执行的一系列命令。
选项参数:-F:输入文件的拆分符
-v:赋值一个用户定义变量
操作准备:sudo cp /etc/passwd ./
sudo chown xxx:xxx passwd
eg:搜索passwd文件以root开头的所有文件行(正则匹配),并输出改行的第7列
eg:搜索passwd文件以root关键字开头的所有行,并输出该行第1列和第7列中以“,”分割
eg:只显示/ect/passwd 的第一列和第七列,以逗号分隔,在所有行前面添加列名user,shell。在最后一行添加“zyy, /bin/hello”
eg:将passwd文件中的用户id(在第三列)增加数值1并输出
内置变量
FILENAME:文件名
NR:已读的记录数
NF:切割后列的个数
eg:统计passwd的文件名,每行的行号,每行的列数
eg:查询空行所在的行号(^:匹配字符串开始的位置;$:匹配字符串结尾的位置)
sort
将文件进行排序,并将排序结果标准输出
1.基本语法
sort [选项] [参数]
选项:-n:按照数值大小排列
-r:倒序排列
-t:设置排序时的分隔字符
-k:指定需要排序的列
数据准备:
eg:按照:分隔后的第2列倒叙排序
面试题:
1.使用linux查询file1中空行所在的行号
awk '/^$/ {print NR} ' file1
2.有文件file1内容如下:
张三 40
李四 60
王五 99
用Linux命令计算第二列的和并输出。
cat file1 | awk -F " " -v sum=0 '{ sum+=$2 } END {print sum} '
3.shell检查一个文件是否存在
4.用shell对文本中无序的一列数字排序
5.用shell查找当前文件夹/home下的所有文本内容中包含“hello”的文件名称