复习:
什么是shell脚本
批处理linux命令的脚本语言
什么脚本 语言?是解释型语言,有解析器来阅读脚本代码。
预设变量
$0 $1$2 $3 $4… $#数量 $*参数的集合 运行脚本文件的时候在命令中添加参数
变量
变量无需定义,可以直接使用,变量名尽量大写, 读取变量的值 $变量名
输入
read -p “qhewhqwkjehklqw” 变量
输出
echo ""不完全输出 可以加入变量的值 ''完全输出 无法使用变量
运算
+ - \* 或者 '*' / %
`expr $NUM1 + $NUM2`
字符串判断
=判断字符串相等
-z判断字符串为空
数值判断
-eq 相等
-ne 不相等
-gt 大于
-ge 大于等于
-lt 小于
-le 小于等于
文件类型
-f 普通文件
-d 目录文件
-e 存在
-L 链接文件
-w 写权限
-x 可执行权限
case结构
case $(变量) in
a)
语句。
;;
b)
语句。
;;
*) # 相当于C语言的default
;;
esac
作业:
- 下面的代码执行后a的值为( 2 )
int a = 10;
if(a = 1) //因为是=运算,所以表达式的结果是=左值,左值是1,所以if条件为真
{
a++;
}
else
{
a--;
}
printf("%d", a);
2 下面的代码a的值是( 10 )
int a = 10;
if(a < 10)
{
a++;
}
- ‘3’ 的Ascii码用16进制表示是( 0x33 ) 10进制是( 51 )。
4 . int main()
{
int a;
scanf("%d", &a);
switch(a)
{
case 1:
printf("Monday\n");
case 2:
printf("Tuesday\n");
case 3:
printf("Wednesday\n");
default:
printf("Error\n");
}
}
如果用户输入了2, 那么输出是( )
Tuesday
Wednesday
Error
-
如果int a = 3, 输出003,那么输出表达式为( printf("%03d", a); )
%d 整数
%nd 输出n位,如果n大于整数的位数,左边补空格,如果n小于整数的位数,完整输出整数。
比如整数123 %5d输出 空格空格123
比如整数123 %2d输出 123
%0nd 输出n位,如果n大于整数的位数,左边补0,如果n小于整数的位数,完整输出整数。
n左边的数字如果要写只能是0
6 .下面的语句有什么错误
int main()
{
int a;
scanf("%d", a); //1 &a
printf("%f", a); //2 %d
return 0;
}
- float money = 12.1, 如果输出的金额保留小数点两位,则输出表达是为( printf("%.2f", money); )
%nf 输出n位
%n.mf 输出n位,小数点后m位
%.mf 不在乎输出位数,只要小数点后m位
- int main()
{
int i = 0, sum = 0;
for(i = 0; i < 100; i++)
{
if(i % 5 == 0)
continue;
sum += i;
}
}
上面程序的作用是( 0~99求和,除了5的倍数 )
- int main()
{
int number = 0;
while(1)
{
scanf("%d", &number);
if(number == 0)
{
break;
}
}
}
上面程序的作用是( 不停的输入整数,直到输入为0结束 )
- for( ; ; ) //for循环只要省略表达式2,就是死循环
上面语句的作用是( 死循环 )
- 下面程序的运行结果为( 0 1 2 4 )。
for(k = 0; k < 5; ++k)
{
if(k == 3)
continue;
printf("%d",k);
}
作业:
编写shell脚本,实现按键 asdw 控制输出上下左右
#!/bin/bash
read -p "input asdw: " INPUT
case $INPUT in
"a")
echo "左"
;;
"s")
echo "下"
;;
"d")
echo "右"
;;
"w")
echo "上"
;;
esac
作业:
编写脚本,实现简单的计算功能。 示例: bash a.sh 3 + 4
#!/bin/bash
case $2 in
"+")
echo `expr $1 + $3`
;;
"-")
echo `expr $1 - $3`
;;
"x")
echo `expr $1 \* $3`
;;
"/")
echo `expr $1 / $3`
;;
esac
1、shell 中的循环
1. for 循环格式:
for NAME in $(单词表)
do
循环语句。
done
单词表是N个字符串的集合,比如 $*是位置参数的集合。
NAME是用来遍历单词表的变量名,在每一次循环体执行中,NAME的值将分别等于单词表的每个单词。
比如:单词表 hehe haha heihei,那么这个for循环将进行3次,在第一次循环体中,NAME 值hehe,在第二次循环体中NAME值是haha,在第三次循环体中NAME值是heihei。
示例:
#! /bin/bash
LIST=“zhao qian sun li zhou”
for NAME in $LIST
do
echo $NAME
done
练习:
请输出 根目录下的所有文件名称 使用for循环
#!/bin/bash
LIST=`ls /` #把ls /本应打印的结果赋值给变量
for FILE in $LIST
do
echo $FILE
done
练习:
请使用循环实现,将 day7 目录中的所有文件,都拷贝到 day8 中。(不使用 cp -r )用循环一个一个文件拷贝
#!/bin/bash
DAY7FILES=`ls day7`
for FILE in $DAY7FILES
do
cp day7/$FILE day8
done
2. while 循环格式:
while [ 条件 ]
do
循环语句。
done
示例:
vi test.sh
#! /bin/bash
M=1
while [ $M -le 100 ]
do
echo “M is $M”
M=`expr $M + 1`
done
//输出1~100
练习:
求 1~100 的和。
#!/bin/bash
SUM=0
M=1
while [ $M -le 100 ]
do
SUM=`expr $SUM + $M`
M=`expr $M + 1`
done
echo $SUM
练习:
使用 while 完成功能: 创建 temp1 ~ temp9 九个文件
#!/bin/bash
M=1
while [ $M -le 9 ]
do
mkdir temp$M
M=`expr $M + 1`
done
shell脚本总结
shell脚本是运行在shell上的脚本程序,用来做linux的命令的批处理。
用户 shell 内核 硬件的关系。
linux系统的特点:
多用户
多任务
方便移植
2、 make (工程管理工具)
作用:提高编译效率。
如果是已经编译过的文件,又没有进行修改,下次编译的时候不再编译。
make : 工程管理工具。 make 命令。
makefile : 是配置文件。 是 make 命令唯一读入的配置文件。
makefile 的名字是固定的。
Makefile或者写成makefile都可以。
工作的时候大概率不会从头编写Makefile文件,但是很可能要对它进行修改。
1. 文件编写规则
目标名称:依赖文件
编译规则
//我们以前使用过的编译命令,在这里test是我们要编译的目标,生成这个目标的文件叫test.c,test.c是test的依赖文件。gcc test.c -o test就是编译规则。
gcc test.c -o test
目标名称:编译最终生成的产物。
依赖文件:编译目标需要的文件。
main是目标,main.c add.c del.c是编译这个目标的依赖文件。依赖文件不一定是.c文件。
还可能是.o文件。
编译规则:编译的指令。
示例:
vi makefile
main:main.c
gcc main.c -o main
执行过程:
linux@ubuntu:~$ make
添加清除和重新编译的功能:
示例:
vi makefile
teris:teris.c
gcc teris.c -o teris
clean:
rm teris
rebuild: clean teris
编译规则要和生成的目标名字保持一致。
make
make clean
make rebuild
2. 多文件处理
1)不标准的写法
main:main.c add.c sub.c mul.c
gcc main.c add.c sub.c mul.c -o main
linux@ubuntu:~/22011$ make
gcc main.c add.c sub.c mul.c -o main
此时我们修改任意一个源文件,发现会将所有的源文件重新编译。达不到makefile应该发挥的效果。
2)改善写法
main:main.o add.o sub.o mul.o
gcc main.o add.o sub.o mul.o -o main
main.o:main.c
gcc main.c -c
add.o:add.c
gcc add.c -c
sub.o:sub.c
gcc sub.c -c
mul.o:mul.c
gcc mul.c -c
3)简洁的写法
main:main.o add.o sub.o mul.o
gcc main.o add.o sub.o mul.o -o main
.o:.c #每个.o文件对应自己同名的.c文件
gcc *.c -c
clean:
rm *.o main #clean的时候,因为生成多个目标,所以需要清理掉所有的目标,包括所有的.o文件以及main
rebuild: clean main
3. 添加变量
1) 预设变量
$@ : 完整的目标名称
$^ : 依赖文件
$< : 每个.o文件的第一个依赖文件
vi makefile
main:main.o add.o sub.o mul.o
gcc $^ -o $@
.o:.c
gcc $< -c
clean:
rm *.o main
rebuild: clean main
2) 将目标等,用变量代替
EXEC=main #把目标的名称放在一个变量里
OBJS=main.o add.o sub.o mul.o #将所有的依赖文件放在一个变量里
CC=gcc #把使用的编译器也放在变量里
$(EXEC): $(OBJS) # main:main.o add.o sub.o mul.o
$(CC) $^ -o $@ # gcc main.o add.o sub.o mul.o -o main
.o:.c
$(CC) $< -c # gcc .o文件对应的.c文件 -c
clean:
rm $(OBJS) $(EXEC) # main.o add.o sub.o mul.o main
rebuild: clean $(EXEC) # clean main
3、 gdb (调试器 GNU debuger)
为什么使用gdb:当我们的代码出现逻辑问题的时候,需要进行调试,此时我们可以选择一个调试工具辅助我们进行调试。gdb就是一个很有名气的调试器。
调试的思想:
调试代码使用的工具不是最重要,要有调试思想。
1 预判可能出现问题的模块。
2 查看关键位置关键变量的值是否正常。
比如:俄罗斯方块,不自动出方块。预判可能是出方块的代码逻辑有问题。此时,我们可以查看生成方块的随机值、再看看方块起始位置的值。
这是断点的思想!!
gdb 的使用示例:
~$ gcc a.c -o a1
~$ gcc a.c -o a2 -g // 添加 -g 选项。 将调试信息写到了可执行文件里。
~$ ls -l
-rwxrwxr-x 1 linux linux 7157 Aug 3 16:50 a1
-rwxrwxr-x 1 linux linux 8129 Aug 3 16:51 a2 // 因为添加了 -g 选项,所以可执行文件要大一些。
使用: gdb a2 // gdb + 执行文件名
gdb 模式中的一些命令:
l : 列出代码(默认10行)
b : 设置断点 breakpoint
r : run 运行程序
n : next 单步运行
p : print 打印各类变量等信息。
c : continue 继续运行
q : quit 退出 gdb 模式
info break: 查看断点信息
delete 断点号: 删除断点
作业:
一 选择题
1.与十六进制数200等值得十进制数为( B )
10 0000 0000
A:256 B:512 C:1024 D:2048
2.下面哪个shell语句不能打印出用户主目录的路径? ( C )
A. echo “$HOME” B. echo ~
C. echo `$HOME` D. echo $HOME
3.switch语句( A )。
A:都可以用if-else if结构实现 B:都不可以用if-else if结构实现
C:有的可以用if-else if结构实现 D:大部分不可以用if-else if结构实现
4.设有定义:int a,*pa=&a;以下scanf语句中能正确为变量a读入数据的是( A )
A:scanf(“%d”,pa); B:scanf(“%d”,a);
C:scanf(“%d”,&pa); D:scanf(“%d”,*pa);
5.1MB等于( D )
A:1000字节 B:1024字节 C:1000*1000字节 D:1024*1024字节
byte 字节 = 8bit位
6.以下代码打印的结果是(假设运行在i386系列计算机上): ( C )
struct st_t
{
int status;
short* pdata;
char errstr[32];
};
40字节
struct st_t st[16];
char* p = (char*)(st[2].errstr + 32); //st[2].errstr得到st[2]里面的errstr数组名,是地址,地址是char类型
//st[2].errstr + 32地址的偏移运算,正好得到st[3] 的地址,将st[3] 的地址转换成char类型地址赋值给p
printf("%d", (p - (char*)(st))); //st是st[0]的地址,将st[0] 的地址转换成char地址,st[3]地址-st[0]地址相差120个字节,因为 (p - (char*)(st))是以char为地址类型,所以一个单位是一个字节。所以最后得到120个单位
地址相减是什么意思?
int a;
int* p = &a;
printf("%p %p\n", p, p+1);//前后两个地址相差4个字节
//地址1+N = 地址2
//地址2-地址1 = N 所以地址相减得到偏移的单位数
A 32 B 114
C 120 D 1112
二:填空
1.C语言源代码编译成a.out的过程中需要经历哪些过程_________预处理 编译 汇编 链接_____。(东软)
2.C 语言运算对象必须是整型的运算符是___%________。(东软)
3.有一个参数为char*,返回值也为char*的函数f,需要定义一个函数指针a,指向函数f,
请写出函数指针a的定义___char *(*a)(char *);_______。
作业:
编一个程序求质数的和,
例如F(7)= 2+3+5+7+11+13 +17 = 58 (笔试综合)
#include <stdio.h>
int isPrime(int num)
{
int i;
for(i = 2;i < num;i++)
{
if(num%i == 0)
{
return 0;
}
}
return 1;
}
int main()
{
int i;
int n;
scanf("%d", &n);
int num = 2;
int sum = 0;
for(i = 0;i < n;)
{
if(isPrime(num) == 1)
{
sum += num;
i++;
}
num++;
}
printf("%d\n", sum);
return 0;
}
作业:(选做,不讲)
编写一个弹出式菜单的shell程序并实现其简单的菜单功能
* MENU *
* 1.copy 2.rename *
* 3.remove 4.exit *
即用户按下数字1,复制
输入数字2,改名
输入数字3 删除
空
1.C语言源代码编译成a.out的过程中需要经历哪些过程_________预处理 编译 汇编 链接_____。(东软)
2.C 语言运算对象必须是整型的运算符是___%________。(东软)
3.有一个参数为char*,返回值也为char*的函数f,需要定义一个函数指针a,指向函数f,
请写出函数指针a的定义___char *(*a)(char *);_______。
作业:
编一个程序求质数的和,
例如F(7)= 2+3+5+7+11+13 +17 = 58 (笔试综合)
#include <stdio.h>
int isPrime(int num)
{
int i;
for(i = 2;i < num;i++)
{
if(num%i == 0)
{
return 0;
}
}
return 1;
}
int main()
{
int i;
int n;
scanf("%d", &n);
int num = 2;
int sum = 0;
for(i = 0;i < n;)
{
if(isPrime(num) == 1)
{
sum += num;
i++;
}
num++;
}
printf("%d\n", sum);
return 0;
}
作业:(选做,不讲)
编写一个弹出式菜单的shell程序并实现其简单的菜单功能
* MENU *
* 1.copy 2.rename *
* 3.remove 4.exit *
即用户按下数字1,复制
输入数字2,改名
输入数字3 删除
. 输入数字4,退出