1、现有成绩文件按“姓名 学校 年级 班级 分数”五列组成,编写Shell脚本,将某目录下所有成绩文件(≥3个)合并为一个,形成“姓名 班级 分数”三列,并按成绩排序,输出年级排名前十。同时输出60以下、60-70、70-80、80-90、90-100各分数区间人数,并统计所有人的平均分。(25分)
先创建三个成绩文件
touch score1.txt score2.txt score3.txt
需要填入内容,以下为随机生成的内容
score1.txt
Aaaa ZhengzhouUniversity 2021 1 76
Alice ZhengzhouUniversity 2021 4 5
Bob ZhengzhouUniversity 2021 9 87
Charlie ZhengzhouUniversity 2021 7 92
David ZhengzhouUniversity 2021 1 15
Eve ZhengzhouUniversity 2021 2 55
Frank ZhengzhouUniversity 2021 5 32
Grace ZhengzhouUniversity 2021 8 68
Hannah ZhengzhouUniversity 2021 10 7
Isaac ZhengzhouUniversity 2021 6 23
Jane ZhengzhouUniversity 2021 3 41
score2.txt
Bbbb ZhengzhouUniversity 2021 2 57
Kevin ZhengzhouUniversity 2021 9 99
Laura ZhengzhouUniversity 2021 7 8
Michael ZhengzhouUniversity 2021 5 51
Nina ZhengzhouUniversity 2021 2 12
Oliver ZhengzhouUniversity 2021 1 95
Patricia ZhengzhouUniversity 2021 8 39
Quentin ZhengzhouUniversity 2021 3 25
Rache ZhengzhouUniversity 2021l 6 75
Sarah ZhengzhouUniversity 2021 4 61
Tom ZhengzhouUniversity 2021 10 48
Ursula ZhengzhouUniversity 2021 9 18
Victoria ZhengzhouUniversity 2021 7 82
score3.txt
Cccc ZhengzhouUniversity 2021 3 89
William ZhengzhouUniversity 2021 5 9
Xavier ZhengzhouUniversity 2021 2 65
Yvonne ZhengzhouUniversity 2021 8 100
Zachary ZhengzhouUniversity 2021 4 36
Anna ZhengzhouUniversity 2021 3 78
Benjamin ZhengzhouUniversity 2021 6 58
Cassandra ZhengzhouUniversity 2021 1 45
Daniel ZhengzhouUniversity 2021 10 28
Eleanor ZhengzhouUniversity 2021 9 85
创建一个目录,把这三个成绩文件放入其中
mkdir score
mv score1.txt score2.txt score3.txt score
scores.sh
#!/bin/bash
# 指定目录和输出文件名
input_dir="/root/score"
output_file="merged_scores.txt"
# 检查目录下文件数量
files=($(find "$input_dir" -maxdepth 1 -type f -name "*.txt"))
if [ ${#files[@]} -lt 3 ]; then
echo "Error: Less than 3 files found in the directory."
exit 1
fi
# 合并所有文件为三列格式
> "$output_file"
for file in "${files[@]}"; do
awk '{print $1, $4, $5}' "$file" >> "$output_file"
done
# 按成绩排序并输出年级排名前十
sort -nr -k3 "$output_file" | head -n 10
# 统计各分数区间的人数和所有人的平均分
awk '
BEGIN {
count = 0
sum = 0
count_a = 0
count_b = 0
count_c = 0
count_d = 0
count_e = 0
}
{
score = $3
sum += score
count++
if (score < 60) count_a++
else if (score >= 60 && score < 70) count_b++
else if (score >= 70 && score < 80) count_c++
else if (score >= 80 && score < 90) count_d++
else if (score >= 90 && score <= 100) count_e++
}
END {
avg = sum / count
print "60以下:", count_a
print "60-70:", count_b
print "70-80:", count_c
print "80-90:", count_d
print "90-100:", count_e
print "平均分:", avg
}
' "$output_file"
执行:./scores.sh
2、系统中有生产者、计算者和消费者3个线程,共享2个容量为n(n≥4)的缓冲区buffer1和buffer2,生产者随机产生小写字母,并放入到buffer1;计算者从buffer1取出字母,将小写字母转换为大写字母,放入到buffer2;消费者从buffer2取出字符,将其打印到屏幕上。试用使用信号量解决生产者、计算者、消费者问题。(25分)
convert.c
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#include <stdlib.h>
#include <ctype.h>
#include <time.h> // 需要包含time.h头文件来使用time函数
#define N 6 // 缓冲区容量
char buffer1[N]; // 缓冲区1
char buffer2[N]; // 缓冲区2
int in1 = 0; // 缓冲区1的索引
int out1 = 0; // 缓冲区1的索引
int in2 = 0; // 缓冲区2的索引
int out2 = 0; // 缓冲区2的索引
sem_t empty1, full1, empty2, full2; // 信号量
void *producer(void *arg) {
// 使用当前时间作为随机数生成器的种子
srand(time(NULL));
while (1) {
sem_wait(&empty1); // 等待空位
buffer1[in1] = 'a' + rand() % 26; // 随机产生小写字母
printf("Producer produced %c\n", buffer1[in1]);
in1 = (in1 + 1) % N;
sem_post(&full1); // 通知有新的数据
}
}
void *computer(void *arg) {
while (1) {
sem_wait(&full1); // 等待数据
sem_wait(&empty2); // 等待空位
buffer2[in2] = toupper(buffer1[out1]); // 转换为大写字母
printf("Computer computed %c\n", buffer2[in2]);
out1 = (out1 + 1) % N;
in2 = (in2 + 1) % N;
sem_post(&full2); // 通知有新的数据
}
}
void *consumer(void *arg) {
while (1) {
sem_wait(&full2); // 等待数据
printf("Consumer consumed %c\n", buffer2[out2]);
out2 = (out2 + 1) % N;
sem_post(&empty2); // 通知有空位
}
}
int main() {
pthread_t tid1, tid2, tid3;
sem_init(&empty1, 0, N); // 初始化信号量
sem_init(&full1, 0, 0);
sem_init(&empty2, 0, N);
sem_init(&full2, 0, 0);
pthread_create(&tid1, NULL, producer, NULL); // 创建线程
pthread_create(&tid2, NULL, computer, NULL);
pthread_create(&tid3, NULL, consumer, NULL);
pthread_join(tid1, NULL); // 等待线程结束
pthread_join(tid2, NULL);
pthread_join(tid3, NULL);
sem_destroy(&empty1); // 销毁信号量
sem_destroy(&full1);
sem_destroy(&empty2);
sem_destroy(&full2);
return 0;
}
编译链接命令:gcc convert.c -o convert
运行命令:./convert
3、通过Linux中的socket通信机制,编写C程序,完成猜数字的游戏。服务端自动生成1~100的随机数,客户端猜数字。猜数字的过程中,根据猜测数据的大小给出大了或小了的反馈,直到猜对,游戏结束。(25分)
sever.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <time.h>
#define PORT 8080
#define BUF_SIZE 1024
int main() {
int server_fd, new_socket;
struct sockaddr_in address;
int addrlen = sizeof(address);
char buffer[BUF_SIZE] = {0};
srand(time(0)); // 初始化随机数种子
int secret_number = rand() % 100 + 1; // 生成1~100的随机数
// 创建socket
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// 设置地址
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);
// 绑定
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
// 监听
if (listen(server_fd, 3) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
// 接受连接
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
perror("accept");
exit(EXIT_FAILURE);
}
// 与客户端交互
while (1) {
memset(buffer, 0, BUF_SIZE);
// 接收猜测
read(new_socket, buffer, BUF_SIZE - 1);
int guess = atoi(buffer);
if (guess > secret_number) {
write(new_socket, "Too high!", 9);
} else if (guess < secret_number) {
write(new_socket, "Too low!", 8);
} else {
write(new_socket, "Correct!", 7);
break;
}
}
// 关闭连接和socket
close(new_socket);
close(server_fd);
return 0;
}
client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#define PORT 8080
#define BUF_SIZE 1024
int main() {
int sock = 0, valread;
struct sockaddr_in serv_addr;
char buffer[BUF_SIZE] = {0};
int guess;
// 创建socket
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("\n Socket creation error \n");
return -1;
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
// 假设服务端IP是127.0.0.1
if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
printf("\nInvalid address/ Address not supported \n");
return -1;
}
// 连接到服务端
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
printf("\nConnection Failed \n");
return -1;
}
// 开始猜数字游戏
while (1) {
printf("Enter your guess (1-100): ");
scanf("%d", &guess);
// 发送猜测
snprintf(buffer, BUF_SIZE, "%d", guess);
write(sock, buffer, strlen(buffer));
// 接收反馈
memset(buffer, 0, BUF_SIZE);
valread = read(sock, buffer, BUF_SIZE - 1);
printf("%s\n", buffer);
// 检查是否猜对
if (strstr(buffer, "Correct!") != NULL) {
printf("Congratulations! You guessed the number correctly.\n");
break;
}
}
// 关闭socket
close(sock);
return 0;
}
实验结果:
4、在Linux 0.12(0.11)上添加两个系统调用,第一个系统调用将字符串内容拷贝到内核中保存下来,第二个系统调用将保存的字符串再拷贝到用户空间。编译并运行添加过新系统调用的Linux系统,要求给出系统调用代码的注释,及系统调用添加、编译和运行时的截图。(25分)
这题是哈工大操作系统实验课的第三个实验,下面提供了课程链接,参与课程就有Linux0.11的实验环境了,后面的自己做吧。
https://www.lanqiao.cn/courses/115
最后,交大作业也是到期末的时候了,以下提供 操作系统第五版费祥林 电子课本和课后答案的链接,祝期末顺利。
通过百度网盘分享的文件:
链接:https://pan.baidu.com/s/1z3KIUaqTRL-0zHPamyk-Bw?pwd=n11p
提取码:n11p
复制这段内容打开「百度网盘APP 即可获取」