OS_lab0
Lab0实验报告
思考题
Thinking 0.1
题面
1 |
|
回答
1.cat Untracked.txt
与cat Stage.txt
命令输出内容的区别在于前者显示README.txt
文件未跟踪,而后者则显示该文件已暂存需要提交,区别于README.txt
文件的状态。同时由于在git add README.txt
和git commit -m “<message>”
这之间创建了Stage.txt
文件,所以在前后者显示的输出中都有Untracked.txt
未被跟踪,而后者此外还有Stage.txt
文件未被跟踪。
Untracked.txt
文件内容如下:
Stage.txt
文件内容如下:
2.cat Modified.txt
命令的输出与第一次add
之前的输出不一样,至于原因,我认为是由于修改后,该文件版本同最近一次提交的版本中的并不相同了,但是这个文件曾经被git add
进入暂存区,也就是被Git
跟踪过了,因此该文件被修改后处于的是被修改的状态,而非未跟踪状态,但是根据Git
提供的提示,仍需要通过git add <filename>
命令来更新暂存区文件。
Modified.txt
文件内容如下:
Thinking 0.2
题面
1 |
|
回答
(摘自Git - 记录每次更新到仓库)
图中的Add the file
代表了git add <filename>
命令表示将未跟踪的文件添加到暂存区中,Stage the file
也是git add <filename>
命令表示将处于修改状态的文件更新至暂存区中,commit
是git commit -m "<message>"
命令表示将暂存区中的文件提交到HEAD
区(也就是最近的一次提交)中。
Thinking 0.3
题面
1 |
|
回答
1.假如print.c
文件并未被跟踪,被错误删除后,将无法采用命令来恢复。假如print.c
被跟踪,也就是被放入暂存区或者是被提交到HEAD
后,可以使用git restore print.c
丢弃在工作区中对于print.c
文件的修改,将print.c
重新恢复回来。本质是将暂存区的版本重新赋给工作区。
2.同1,若print.c
未被跟踪,错误删除时就不可再用命令来恢复。若被跟踪,则可以先使用git reset HEAD print.c
来撤销对暂存区的修改,也就是恢复到仅在工作区删除print.c
的状态,然后再使用git restore print.c
将暂存区赋给工作区,恢复print.c
文件。
3.可以采用git rm --cached hello.txt
,将该文件从暂存区删除但并没有在工作区中删除,仅起到移除的作用。
Thinking 0.4
题面
1 |
|
回答
1.使用git reset --hard HEAD^
后HEAD
会回退到前一个git commit
之前的状态,也就是回退到上一个版本,此时使用git log
会显示当前处于第二次git commit
后的状态。
2.再使用git reset --hard <hash>
会直接切换到哈希值为<hash>
的提交状态,因此每次使用该命令移动的都是HEAD
这个指针,因此使用该命令可以进行版本回退和前进。因此,每次使用该命令后执行git log
显示的就是以当前HEAD
所指向的提交版本及此之前的版本组成的提交日志。
Thinking 0.5
题面
1 |
|
回答
echo first
将输出first
到终端上;
echo second > output.txt
将会将second
输出到output.txt
文件中;
echo third > output.txt
将会用third
覆盖掉原有的second
;
echo forth >> output.txt
将会将forth
追加到output
文件中third
之后。
Thinking 0.6
题面
1 |
|
回答
command文件内容:
result文件内容:
结果解释:test文件内容如下:
当以shell
脚本批处理时,第4、6、8行代码会分别将a、b、c赋值为1、2、3.再者经由11、13、15行代码将c、b、a的结果输入到file1
、file2
、file3
中,第15、16、17行代码再将file1
、file2
、file3
的内容输出到file4
中,其中file1
覆盖输入,file2
和file3
均是追加输入,第19行代码再将file4
的内容追加输入到result
文件中。
因此,运行后,result
文件中的每行内容分别为file1
、file2
、file3
的内容,也就是c、b、a,即3、2、1。
Thinking A.1
题面
1 |
|
回答
1.由于页面大小为4KB,虚拟地址空间为512GB,则一共有128M个页表项,且这些页表项同虚拟地址空间线性映射,因此PTbase对应的应该是第(PTbase >> 12)个页表项(其中一个页表项代表一个页目录项)。因为一个页表项占8B,则第(PTbase >> 12)个页表项相对于页表基地址的偏移为(PTbase >> 12) * 8,则二级页表页目录的基地址为(PTbase >> 12) * 8 +PTbase = PTbase >> 9 + PTbase。同理可得:三级页表页目录基地址为(PTbase >>18 + PTbase >>8 + PTbase)。
2.映射到页目录自身的页目录项(自映射),题目要求不明,并不知道是要要求什么?是要求页目录项的内容还是地址?如果是内容的话,未知,无法求解。如果是地址的话,同第一问:应该是(PTbase>>27 + 3 * PTbase>>18 + 3 * PTbase>>9 + PTbase)。
lab0课下的一些可能的易错点和踩的坑
Exercise 0.1
1.palindrome.c
的编写,回文数的判断,我的思路是先将输入的n
按每一位分解到一个数组中,然后从数组头尾进行比较,一旦发现不同就输出N
,这个应该都不会出错吧!
2.将.c
文件编译成可执行文件的方式为:gcc xxx.c -o xxx
;也可以先只编译然后再链接:gcc -c xxx.c -o xxx.o
、gcc xxx.o -o xxx
。
3.获取某个文件的某一行的内容可以使用sed
命令,通过sed -n '{num}p' xxx.txt
可以从xxx.txt
文件获取其{num}
行的内容并显示在终端上,当然你可以通过重定向将输出内容输出到文件中,注意:>是覆盖式输出,而>>才是追加式输出。
Exercise 0.2
1.shell
里内声明定义的变量需要前置$
才可使用,并且使用的时候是直接替换,部分用法和宏有点**”类似”**。
例如:
1 |
|
2.注意,循环里循环变量的改变,在shell
中,可以通过如下方式进行:a=$[$a+1]
,通过询问GPT,我得知了[$a+1]
是旧式的算术式,其将告诉shell
将[$a+1]
当作算术式计算,最终得到”2”的结果后再赋给a
,但是GPT并不推荐它,确实令人很难以理解,此外其推荐了如下的新式算术扩展:
1 |
|
3.删除非空的目录,可不能再用rmdir
了,它只能删除空的,那该怎么办呢?注意到rm
的-r
选项好像也可以删除目录啊,因此我采用rm -rf filex
,这里要注意了哈,从打出-rf
高亮为红色,也可以看出,这是个危险的命令选项,因此,我们只要删除要我们删除的目录即可,**切勿执行rm -rf *
或rm -rf ./*
**,否则后果不堪设想。
Exercise 0.3
1.可以使用grep
命令查找有xxx
字符的地方,通过加上**-n
选项可以显示相应的行数,利用通道将输出作为输入给awk
命令,此前,可以先执行一下grep
命令的输出格式,观察到相应使用的分隔符后,即可在修改分隔符的基础上利用awk
命令输出行数**。
Tips:传参的时候如果最终的命令形式是文件或字符串一类的,可以用双引号括起来,这样可能会减少”歧义”。
Exercise 0.4
1.使用sed
命令可以实现字符串的替换,记得加上-i
选项才会对源文件修改啊!-n
只是安静模式哟,只会输出改后的效果,但是并不改(我会输出,但是我不改)。此外,带上/g
才会全部替换,否则,替换的只会是每行的第一个匹配的。
2.code
文件夹内的fibo.c
依赖于本文件夹内的main.c
和另一个文件夹的fibo.h
,因此在相应的编译的过程中需要使用-I
选项来指定头文件的路径,例如:-I../csc
就是告诉shell
有个头文件在前一个目录的csc
文件夹内。此外,最终生成的时候一定要把所有有参与到达文件一块链接,否则,大有出现找不到入口的bug的情况。
3.不确定的地方一律使用绝对路径,当然由于评测机的根路径会与我们的本地有所不同,因此,应该确保你使用的决对路径里没有题目提供的文件树以外的东西,否则,会出现编译错误的情况,都找不到了可不出错了。
4.make
内近似于并行执行,因此,你原先设定的顺序并不一定是最终的执行顺序,可以使用以下三种方式解决:
此处摘自Make 命令教程 - 阮一峰的网络日志)
1.把两行命令写在一起,中间用分号分隔:
1
2
var-kept:
export foo=bar; echo "foo=[$$foo]"2.在换行前加反斜杠转义\:
1
2
3
var-kept:
export foo=bar; \
echo "foo=[$$foo]"3.加上
.ONESHELL:
命令:
1
2
3
4
.ONESHELL:
var-kept:
export foo=bar;
echo "foo=[$$foo]"
上机前需要注意的
最好在每个脚本文件末尾手动写一个
exit 0
来避免报错,$?
是上一条语句返回值,$#
代表传参个数,$*
代表内容包含所有参数的字符串。文件处理三剑客
grep
、sed
、awk
,一定要熟练掌握,例:如何输出hello.c
中所有包含"os_hello"
(区分大小写)的行的”os_hello”左边的内容,若一行出现多个,则输出第一次出现的左边的内容。grep
+sed
:1
grep -E '.*os_hello' hello.c | sed -E 's/(.*)os_hello.*/\1/'
(不推荐,太过于复杂了,如果你能轻松编写的话,那
当我没说)awk
:1
2
3
4
5awk -F 'os_hello' '{print $1}' hello.c #这是一种错误的写法,这样会导致没有'hello'的那一行将会整行输出。
#如下是正确的写法(即先利用grep命令找到有hello的每一行,然后再利用awk来输出以'hello'为分隔的第一块内容):
grep 'os_hello' hello.c | awk -F 'os_hello' '{print $1}'
awk '/os_hello/ { sub(/os_hello.*/,"");print}' hello.c #也不是很推荐,过于复杂了#var
获取变量var
长度,${#var}
获取长度值${variable:start:count}
表示从变量variable
的start
开始截取count
个字符(超出末尾,截取至末尾)if
需要fi
进行闭合>>
在文件中追加会自动换行,不换行可以采用echo -n xx >> xx
在脚本文件中,输出文件内容,一般采用
cat
,不能用more
,后者是交互式命令,在终端使用。awk
用法补充:1
2#awk+if
awk '{if($2=="'$PID'") print $3}' $FILE可以通过
"'$VAR'"
的形式在awk
中使用shell
中定义的变量。可以使用倒引号将
awk
结果赋值给变量,例如:1
var=`echo $result|awk '{print substr($result,16,3c)}'`
课上感受和踩坑教训
1.一开始由于没有初始化分支,导致后续的fetch
、checkout
等操作都毫无作用,耽搁了4、5分钟,还影响了心态,一定要先初始化分支!!!
2.第一个Makefile
的编写还算顺利,就是后续提交的时候,clean
目标明明本地不加-f
都可以进行有效的操作,但是交到评测机上就是不行,一开始还以为是什么奇怪的地方出了问题,结果是没加-f
,QAQ。(不过试后,一位舍友没加-f也能过,形式还与我没加-f相同,不知道怎么回事()。
3.第二个bash
脚本的最后一个编写出现了些许小问题,导致被卡了很久。也就是并未充分掌握好sed
命令的用法,主要是其中单形参的考虑。题目要求在单形参时,输出相应文件从第形参行开始到最后一行每一行的内容,显然应该使用sed
命令来实现,由于''
中一切皆字符,所以使用""
方便来引用输入的形参,根据$
表示最后一行,得出了第一版想法:
1 |
|
但是如你所见,bash
认为$p
连在一起应该指代一个变量,于是就水灵灵的报错了。
在百般尝试后,(包括但不限于使用,
分隔)最终得到了以下两种方式:
1 |
|
4.extra
题量大,考量全面,拼尽全力,无法拿分,没有办法,菜就多练。
致谢
页表那道题,是在和舍友kxq同学讨论后的结果,特此致谢。