OS-lab0-往年

Dracary 发布于 2026-03-20 280 次阅读


lab0-extra-2025

给出一些TIPS:

如果题目要求创建文件夹,不管有没有递归,建议使用-p,不仅可以递归构建还可以在目标文件夹已经存在时不报错;

如果要清空一个文件,可以使用: > filename

if [[ 表达式 运算符 表达式 ]]对于该式,表达式和运算符之间要加入空格,表达式和旁边的括号之间要加入空格,但是我们进行赋值运算时却不能加入空格,例如a=1

genCode

要求遍历code文件夹下面的所有*.sy文件,我们可以:

for file in ./code/*.sy
do
    name=$(basename $file .sy)
    echo $name
done

接着按照题目要求我们正常执行插入与替换即可:

sed "1i #include\"include/libsy.h\"" ./code/${name}.sy | sed "s/getInt/getint/g" > ./codeSet/${name}.c 

不使用管道也可以,-e允许我们执行多个命令:

sed -e "1i #include\"include/libsy.h\"" \
    -e "s/getInt/getint/g" \
    ./code/${name}.sy > ./codeSet/${name}.c

selectCode

判断文件是否存在:

if [[ -e testfile.c ]]
then
    rm -rf testfile.c
fi

软链接操作,记得加入-s否则就是硬链接,ln的用法为ln -s 源文件或目录 软链接文件或目录,再加上最后的编译步骤得到(补充-I需要的是文件夹不是文件):

ln -s codeSet/$1.c testfile.c
gcc -Iinclude testfile.c -o test.out

selectData

这题比较简单,代码如下:

#!/bin/bash
mkdir -p dataSet
if [[ $1 == "all" ]]
then
    cp -r data/*.in data/*.out dataSet/
else
    cp -r data/${1}_*.in data/${1}_*out dataSet/
fi

补充一点就是加上-rcp会递归复制,这一点即使复制的只是文件也不会报错,所以可以加上

此外cp -r src1 src2 src3 ... dst你要复制的东西可以很多,只要最后一个目标文件夹即可

testProgram

这道题首先要去我们创建目录和清空文件,可以使用:

mkdir -p output
:> testRes.txt

接下来又是经典的遍历文件,同时重定向输入与输出:

for file in dataSet/*.in
do
    name=$(basename $file .in)
    ./test.out < dataSet/${name}.in > output/${name}.out
done

接着要求我们比较两个文件是否不同,这里可以使用diff,如果两个文件完全相同,$?将被置零,同时为了避免diff污染终端,我们重定向它的输出:

diff output/${name}.out dataSet/${name}.out >/dev/null
if [[ $? -eq 0 ]]
then
    echo "$name 1" >> testRes.txt
else
    echo "$name 0" >> testRes.txt
fi

最后它要求所有文件对如果都没有差异,就在首行插入1,也就是:

if [[ $flag -eq 0 ]]
then
    sed -i "1i 1" testRes.txt
else
    sed -i "li 0" testRes.txt
fi 

于是我们得到完整代码:

#!/bin/bash
mkdir -p output
:> testRes.txt
flag=0
for file in dataSet/*.in
do
    name=$(basename $file .in)
    ./test.out < dataSet/${name}.in > output/${name}.out
    diff output/${name}.out dataSet/${name}.out >/dev/null
    if [[ $? -eq 0 ]]
    then
        echo "$name 1" >> testRes.txt
    else
        echo "$name 0" >> testRes.txt
        flag=1
    fi
done
if [[ $flag -eq 0 ]]
then
    sed -i "1i 1" testRes.txt
else
    sed -i "li 0" testRes.txt
fi

viewData

做这题之前我们先来学习一下sort

对于给定的数据:

#input.txt
banana
apple
cat

使用sort <input.txt默认按字典序排序得到

apple
banana
cat

按字典序降序排列sort -r <input.txt得到

cat
banana
apple

接下来是一些进阶用法,给定数据

banana 1
apple 5
cat 3

我们使用sort实际上是对整行的字典序进行升序排列,如果你区分特定列,请使用-k,一般而言默认的分隔符是空格和制表符,-k可以叠加,越靠前作为关键字的优先级越高,-n代表按照数值排序,指定第2列推荐使用-k2,2,而不是-k2,后者代表第二列到行尾,可能会影响排序

如果你需要指定分隔符为;可以使用sort -t; -k2,2n

对于上面的数据我们可以使用sort -k2,2n -k1,1

回到本题,我们得到:

#!/bin/bash
if [[ $1 == "focus" ]]
then
    sed -n "1p" testRes.txt
    sed -n "2,\$p" testRes.txt | sort -k2,2n -k1,1r
elif [[ $1 == "wrong" ]]
then
    sed -n "2,\$p" testRes.txt | grep " 0\$" | sort -k1,1r
else
    grep "$2" testRes.txt
fi

lab0-2021

可能是我搜集资料的问题,感觉这一年的题目难度和量都不大......

首先是题目描述:

当前目录下dir下还有6个子目录,为dir0~dir5,每个子目录下又有lab0_0~lab0_56个文件,某个子目录下还有一个叫做lab0_x的文件。

要求:

  1. 对于dir目录下,所有内容中含hello OS lab0的文件,按如下格式覆盖输出到lab0_exam.c
  2. 如下格式lab0_x文件的路径追加输出到lab0_exam.c
dir/dir0/lab0_0:1:hello OS lab0 hello
dir/dir0/lab0_1:1:hello OS lab0_exam
dir/dir1/lab0_x

于是我们直接上代码,唯一需要注意的就是使用grep时要加入递归符号-r同时记得文件夹要使用dir而不是./dir

于是我们得到第一步的代码:

grep -nr "hello OS lab0" dir > lab0_exam.c

接着是第二步的代码,由于实际上我们不知道lab0_x在哪,所以我们可以使用find来搜索,需要注意的是这里来也需要使用dir而不是./dir,如果担心搜索到文件夹可以在加上参数-type f

于是我们得到第二步的代码:

find dir -type f -name "lab0_x" >> lab0_exam.c

还有一题是Makefile这里暂略

接下来是extra部分,也是暂略Makefile

题目描述如下:

补全script.sh脚本,使得执行bash script.sh file,能够将file文件第8行作为programAstdin,将结果覆盖输出到outputA文件中。

注:file可以是任意的文件

这个有一点小tricks,如果使用:

./programA < $(sed -n "8p" $1) > outputA 

这个命令行是无法得到我们需要的结果,因为脚本会把sed -n "8p" $1的结果当作一个文件名来访问,这是不对的,正确解法应该是使用管道:

sed -n "8p" $1 | ./programA > outputA

lab0-2022

来讲一下关于cp的几个有意思的点:

考虑cp file dir/

该命令行会把文件file复制到文件夹dir下面,也就是得到dir/file

如果是cp -r dir2 dir/,该命令行就会把文件夹dir2递归复制到文件夹dir下面,也就是得到dir/dir2

如果实际上file或者dir不存在,就会报错

再考虑cp file dir

如果dir存在,会复制该文件生成dir/file

如果dir不存在,那么会复制文件file的内容并且重命名为dir

同样的如果我们使用cp -r dir2 dir,如果dir不存在就会递归复制并且重命名该文件夹dir2得到dir

所以我们考虑操作

再复制一份hello_os.o文件到hello_os_dir文件夹内,并将其命名为hello_os

就可以这么做:

cp hello_os.o hello_os_dir/hello_os

这里由于hello_os不存在,所以会单独创建它实现重命名

第二个比较有意思的点就是:

往hello_os.txt中输出hello_os.c中所有包含“os_hello”(区分 大小写)的行的“os_hello”(区分大小写)以左的内容,如果 一行出现多个,则输出第一次出现以左的部分。

对于这道题我们将使用sed来实现删除操作,不过使用下列正则时记得使用sed -E(补充一下sed -e是使用多个sed命令,和大写的命令不一样,并且sed -e -e有先后顺序之分)

下面我将讲解. + * ?

正则里.代表任意字符,*代表前一个字符重复0次或多次,+代表前一个字符重复1次或多次,?代表前一个字符重复0次或1次

于是我们得到:

使用.*可以匹配任意字符串包括空字符串,比如"","apple","banana"等等,

使用OS.*可以匹配OS加上任意字符串以及它本身,比如"OS Hello","OS","OS kkk"等等

使用OS.+可以匹配OS加上任意字符串但不包括它本身

使用OS.?可以匹配OS加上任意单个字符并且包括它本身

使用OS*可以匹配"O","OS","OSSS"

使用OS+可以匹配"OS","OSS","OSSS"

使用OS?只能匹配"O","OS"

所以按照题目要求:

grep "os_hello" hello_os.c | sed "s/os_hello.*//" >hello_os.txt

接下来是extra部分,首先是字符串替换,要求替换给定文件中的所有问号:

sed "s/?//g" $1 > input.txt

接下来是判断文件中是否存在单词legal,我的作法是先使用grep,然后使用wc -l统计行数,非0即可

lines=$( grep "legal" input.txt | wc -l )
if [[ $lines -gt  0 ]]
then
    echo "yes" >>input.txt
else
    exit
fi

不过也有更加高级的做法,使用grep -q进行静默匹配,如果匹配成功,$?=0,匹配失败则置一

grep -q "legal" input.txt
if [[ $? -eq 0 ]]
then
    command
else
    exit
fi

最后一部分是难点,告诉我们第一行是一个01字符串,并且只有一个1,同时也告诉我们字符串的总长度n,要求我们统计1所在的位置

我的思路很简单,甚至没有利用字符串总长度,就是删除1及其后面的所有行内字符,然后统计剩余字符数

nn=$( sed -n "1p" $1 | sed -E "s/1.*//g" | wc -c )
echo -n "$nn" >>input.txt

这里wc -c会算上换行符,但是我们本身要计算的也是1的位置,所以刚好加一就不做处理了

此外,这里的echo -n表示输入时不加上换行符,一般是默认加换行符

这里刚好进行一些正则化字符匹配的实战,对于0000000010000000000000

我们可以使用sed -E "s/^.*1//"来匹配删除"0000000001",需要注意的是^$只是提供位置,不能作为具体的字符,所以sed -E "s/^*1//"不对,此外,更具体一点我们也可以使用sed -E "s/^[0-9]*1//"来匹配

还需要强调的是sed -E "s/^[0-9]{11}//"代表删除开头的11个数字,而sed -E "s/^[0-9]11//"则是删除开头的011,111,211,311等组合

这里是紫罗兰的永恒花园
最后更新于 2026-03-23