目录
Shell脚本
1.shell脚本基础概念
1.1 概念
shell使用方式:手动在命令行下命令和用shell脚本
shell脚本本质:shell命令的有序集合,扩展名可以为sh见名知意,也可以没有。
shell 既是应用程序,又是一种脚本语言(应用程序 解析 脚本语言)。
解释型语句:不需要编译,解释一条执行一条,python、shell脚本。
编译型语句:需要用编译器gcc,g++来进行编译,比如C语言
1.2 创建和执行
新建一个shell脚本: touch xx.sh
第一行必须为: #!/bin/bash
意思是使用/bin/bash来解释执行
执行方式:
- 使脚本具有执行权限: chmod 权限 xx.sh
- 执行: ./xx.sh
练习:
1)在当前路径下创建file_1到file_5, 5个普通文件
2)删除 file_2和file_3文件(使用通配符)
3)将剩下的file文件用tar压缩成bz2的格式
4)将压缩文件复制到家目录下
5)进入到家目录解压压缩文件
6)删除压缩包
2.变量
2.1 用户自定义变量
一般用大写
进行赋值用=,左右两边不能有空格
引用变量前面加$
2.2 位置变量
$0或者${0}是命令行的第一个参数,也就是包含脚本名的参数./xx.sh
$1,$2...就是剩下的第二个第三个命令行参数了,以此类推
$# 所有命令行参数的个数(除了第一个命令行参数)
$@或者$* 所有命令行参数(除了第一个命令行参数)
C语言命令行参数复习:
2.3 预定义变量
$? 前一个命令的退出状态(0为真非0为假)
$$ 正在执行进程的ID号
2.4 环境变量
环境变量一般是指在操作系统中用来指定操作系统运行环境的一些参数,如:临时文件夹位置和系统文件夹位置等。
HOME: /etc/passwd文件中列出的用户主目录
PATH :shell搜索路径,就是是一系列目录,当执行命令时,linux就在这些目录下查找。
3.功能语句
3.1 说明性语句
以#开头是注释,起解释说明作用
3.2 功能性语句
3.2.1 read
功能:read从标准输入读入一行,并且赋值给后面的变量
格式:read V1 V2 V3
把读入行中的第一个单词赋值给V1变量,第二个单词赋值给V2,以此类推,把其余所有单词赋值给最后一个变量。
read -p "提示语句" 变量列表: 可以将提示语句输出,同时输入变量
3.2.2 expr
expr 表达式
注意:表达式符号间必须用空格,元素要用$引用
可以直接输出结果,不过脚本里一般结合命令置换符把结果重新赋值给其他变量。
算术运算符命令expr主要用于进行简单的整数运算,包括加(+)、减(-)、乘(\*)、整除(/)和取余数(%)等操作, 小括号前面也要加\。
练习1:通过expr实现变量自加运算(++i)
#!/bin/bash
I=0
#I=`expr $I + 1`
((++I))
echo $I
3.2.3 test
可测试对象三种:字符串 整数 文件属性
每种测试对象都有若干测试操作符
1)字符串的测试:
s1 = s2 测试两个字符串的内容是否完全一样
s1 != s2 测试两个字符串的内容是否有差异
-z s1 测试s1 字符串的长度是否为0
-n s1 测试s1 字符串的长度是否不为0
2)整数的测试:
a -eq b 测试a 与b 是否相等 equal
a -ne b 测试a 与b 是否不相等 not equal
a -gt b 测试a 是否大于b greater than
a -ge b 测试a 是否大于等于b greater equal
a -lt b 测试a 是否小于b litter than
a -le b 测试a 是否小于等于b litter equal
3)文件属性的测试:
-d name 测试name 是否为一个目录
-f name 测试name 是否为普通文件
-e name 测试文件是否存在
-e name 测试文件是否存在
#!/bin/bash
#测试字符串
VAR="hello"
test $VAR = "hello"
echo $?
test $VAR != "hello"
echo $?
test -z $VAR
echo $?
test -n $VAR
echo $?
#测试整数
test 10 -eq 5
echo $?
test 10 -ne 5
echo $?
test 10 -gt 5
echo $?
test 10 -lt 5
echo $?
#测试文件属性
read -p "input filename: " FILE
test -e $FILE
echo $?
test -f $FILE
echo $?
test -d $FILE
echo $?
3.3 结构性语句
3.3.1 if语句
基本结构:
if 条件
then
命令表1
else
命令表2
fi
多路分支结构:
if 条件1
then
命令表1
elif 条件2
then
命令表2
fi
嵌套结构:
if 条件1
then
if 条件2
then
命令表1
fi
else
命令表2
fi
if可以结合着test判断:
也可以使用操作符[],但是需要前后有空格
补充操作符:
-o 或运算 例如 [ $a -lt 20 -o $b -gt 100 ] 返回 true
-a 与运算 例如 [ $a -lt 20 -a $b -gt 100 ] 返回 false
! 非运算 例如 [ ! false ] 返回 true
&& 逻辑与 例如 [[ $a -lt 100 && $b -gt 100 ]] 返回 false
|| 逻辑或 例如 [[ $a -lt 100 || $b -gt 100 ]] 返回 true
| 位或 例如 echo $[2|2]
&位与 例如 echo $[2&1]
3.3.2 case 语句
格式:
case 变量 in
模式1)
命令表1
;;
模式2)
命令表2
;;
*)
命令表n
;;
esac
例子:
#!/bin/bash
read -p "input number: " NUM
case $NUM in
1)
echo "1"
;;
10)
echo "10"
;;
100|9[0-9])
echo "90-100"
;;
*)
echo "other"
;;
esac
练习:学生成绩管理系统,用shell中的case实现
90-100:A
80-89:B
70-79:C
60-69:D
<60:不及格
#!/bin/bash
read -p "input number: " NUM
case $NUM in
9[0-9]|100)
echo "A"
;;
8[0-9])
echo "B"
;;
7[0-9])
echo "C"
;;
6[0-9])
echo "D"
;;
[1-5][0-9]|[0-9])
echo "lost!"
;;
*)
echo "input err"
;;
esac
3.3.3 for循环
格式:
for 变量名 in 单词表
do
命令表
done
变量依次取单词表中的各个单词, 每取一次单词, 就执行一次循环体中的命令。循环次数由单词表中的单词数确定。命令表中的命令可以是一条, 也可以是由分号或换行符分开的多条。
for语句的几种书写格式:
1)for i in 1 2 3 4 do....done :
变量i从单词表中取值
2)for i do...done:
变量i从命令行取值,可以省略in单词表
3)for i in {1..10} do...done:
变量i从1-10个数中取值
4)for ((i = 0; i < 10; i++)) do...done:
书写格式类似c语言
3.3.4 while
格式:
while 命令或表达式
do
命令表
done
while语句首先测试其后的命令或表达式的值,如果为真,就执行一次循环体中的命令,然后再测试该命令或表达式的值,执行循环体,直到该命令或表达式为假时退出循环。
练习:分别用for和while实现1-10求和
#!/bin/bash
NUM=0
i=1
while test $i -le 10
do
((NUM=NUM+i))
((i++))
done
echo $NUM
#####################
SUM=0
for ((i=1;i<=10;i++))
do
((SUM=SUM+i))
done
echo $SUM
3.3.5 循环控制语句
break n: 结束n层循环
continue n: 结束n层的本次循环,继续下一次循环
#!/bin/bash
for ((i=0;i<5;i++))
do
for ((j=0;j<5;j++))
do
if [ $j -eq 3 ]
then
#break 1
#break 2
#continue 1
continue 2
fi
echo "$i : $j"
done
done
4.数组
4.1 数组的赋值
- arr=(1 2 3 4 5)
- arr=($1 $2 $3...)
- read a b c
arr=($a $b $c)
- read -a arr
4.2 数组的调用
${arr[i]} #引用数组元素,数组元素下标从0开始到n-1结束
arr[i]=10 #对数组元素重新赋值
${arr[@]} #遍历数组
${#arr[@]} #数组元素的个数
例子:
练习:从终端输入3个整数,输出三个数中的最小值
冒泡排序:
5.函数
5.1 函数定义方式
- 函数名()
{
命令表
}
- function 函数名()
{
命令表
}
5.2 函数调用
函数名 参数列表
#!/bin/bash
fun ()
{
echo "hello world"
}
function add()
{
((NUM=$1 + $2))
echo $NUM
}
fun
add 1 2
函数内 $1 $2 表示的是传递给函数的参数
结构体复习:
#include <stdio.h>
#include <string.h>
/* 结构体定义格式:
struct 结构体名
{
成员列表;
};
*/
struct stu
{
int id;
char name[32];
float score[3];
};
int main(int argc, char const *argv[])
{
//定义结构体变量的同时给每个成员赋值
struct stu s2 = {1, "xiaoming", {12, 34, 56}};
//定义结构体变量格式: struct 结构体名 结构体变量名;
struct stu s1; //先定义结构体变量,然后给每个成员单独赋值
s1.id = 2;
strcpy(s1.name, "xiaofang");
s1.score[0] = 100;
s1.score[1] = 90;
s1.score[2] = 80;
//定义结构体指针格式:struct 结构体名 *结构体指针名;
struct stu *p = &s1;
p->id = 3; // s1.id = 3;
strcpy(p->name, "xiaomei");
p->score[0]=99;
printf("%d %s %f\n", s1.id, s1.name, s1.score[0]);
return 0;
}
补充结构体对齐原则:
1)第一个成员在相对于结构体变量起始位置偏移量offset为0的地址处(通俗点来说,就是第一个成员变量的地址与结构体起始位置的地址是相同的),以后每个成员按定义顺序依次存放在offset为该数据成员大小的整数倍的地方,只有double类型存放在4的整数倍的地方(比如int在32位机器位4字节,要从4的整数倍开始存储)。
2)用结构体里面最大的数据类型的大小和8(32位系统和4)进行比较,按照字节数小的为单位开辟空间。
练习:
判断当前路径下是否存在目录aa,如果不存在创建;遍历当前路径下的文件,如果是普通文件,将文件复制到aa目录下,并计算文件的个数。
参考:
#!/bin/bash
if test -d "aa"
then
echo 存在aa
else
mkdir aa
fi
NUM=0
for file in `ls` #for file in *
do
if test -f $file
then
cp $file aa
((NUM++))
fi
done
echo $NUM
2.做一套面试题