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
补充一点就是加上-r时cp会递归复制,这一点即使复制的只是文件也不会报错,所以可以加上
此外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的文件。要求:
- 对于dir目录下,所有内容中含
hello OS lab0的文件,按如下格式覆盖输出到lab0_exam.c中- 按如下格式将
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行作为programA的stdin,将结果覆盖输出到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等组合

Comments NOTHING