北航操作系统Lab0实验报告

2025-03-27

初识Linux操作系统,了解bash、make以及git的基本指令

Thinking 0.1

  • 在前述已初始化的~/learnGit 目录下,创建一个名为 README.txt 的文件。执行命令git status > Untracked.txt。
  • 在README.txt 文件中添加任意文件内容,然后使用 add 命令,再执行命令 git status > Stage.txt。
  • 提交README.txt,并在提交说明里写入自己的学号。
  • 执行命令cat Untracked.txt 和 cat Stage.txt,对比两次运行的结果,体会README.txt 两次所处位置的不同。
  • 修改README.txt 文件,再执行命令git status > Modified.txt。
  • 执行命令cat Modified.txt,观察其结果和第一次执行 add 命令之前的 status 是否一样,并思考原因。
git@23373387:~/learnGit $ touch README.txt
git@23373387:~/learnGit $ git status > Untracked.txt
git@23373387:~/learnGit $ vim README.txt
git@23373387:~/learnGit $ git add README.txt
git@23373387:~/learnGit $ git status > Stage.txt
git@23373387:~/learnGit $ git commit -m "23373387"
[master (根提交) ca296b7] 23373387
 1 file changed, 1 insertion(+)
 create mode 100644 README.txt
git@23373387:~/learnGit (master)$ cat Untracked.txt
位于分支 master

尚无提交

未跟踪的文件:
  (使用 "git add <文件>..." 以包含要提交的内容)
        README.txt
        Untracked.txt

提交为空,但是存在尚未跟踪的文件(使用 "git add" 建立跟踪)
git@23373387:~/learnGit (master)$ cat Stage.txt
位于分支 master

尚无提交

要提交的变更:
  (使用 "git rm --cached <文件>..." 以取消暂存)
        新文件:   README.txt

未跟踪的文件:
  (使用 "git add <文件>..." 以包含要提交的内容)
        Stage.txt
        Untracked.txt

git@23373387:~/learnGit (master)$ vim README.txt
git@23373387:~/learnGit (master)$ git status > Modified.txt
git@23373387:~/learnGit (master)$ cat Modified.txt
位于分支 master
尚未暂存以备提交的变更:
  (使用 "git add <文件>..." 更新要提交的内容)
  (使用 "git restore <文件>..." 丢弃工作区的改动)
        修改:     README.txt

未跟踪的文件:
  (使用 "git add <文件>..." 以包含要提交的内容)
        Modified.txt
        Stage.txt
        Untracked.txt

修改尚未加入提交(使用 "git add" 和/或 "git commit -a"
  • README.txt新建的时候,README.txt 处于未跟踪状态,Git 还没有对该文件进行版本管理。这是因为刚创建的文件,Git 不会自动将其纳入版本控制,需要使用 git add 命令将其添加到暂存区。
  • 执行 git add README.txt 后,README.txt 被添加到了暂存区,处于待提交状态。暂存区是一个中间区域,用于准备要提交到版本库的文件。
  • 当修改 README.txt 后,它处于已修改但未暂存的状态。这和第一次执行 add 命令之前的状态不同,第一次 README.txt 是未跟踪文件,而现在它已经是版本库中的文件,只是内容被修改了,需要再次使用 git add 命令将修改添加到暂存区,才能提交这些变更。

Thinking 0.2

仔细看看0.10,思考一下箭头中的add the file、stage the file和commit分别对应的是Git里的哪些命令呢?

  • add the file、stage the file都指的是将文件添加到 Git 的暂存区这一操作,在 Git 里,对应的命令是 git add。
  • commit 指的是将暂存区中的变更永久保存到本地仓库的历史记录中,在 Git 里,对应的命令是 git commit。

Thinking 0.3

  • 代码文件print.c被错误删除时,应当使用什么命令将其恢复?
  • 代码文件print.c被错误删除后,执行了git rm print.c命令,此时应当使用什么命令将其恢复?
  • 无关文件hello.txt已经被添加到暂存区时,如何在不删除此文件的前提下将其移出暂存区
git checkout -- print.c

git reset HEAD print.c
git checkout -- print.c

git rm --cached hello.txt

Thinking 0.4

  • 找到在/home/22xxxxxx/learnGit下刚刚创建的README.txt文件,若不存在则新建该文件。
  • 在文件里加入Testing 1,git add,git commit,提交说明记为1。
  • 模仿上述做法,把1分别改为2和3,再提交两次。
  • 使用git log命令查看提交日志,看是否已经有三次提交,记下提交说明为3的哈希值a。
  • 进行版本回退。执行命令git reset –hard HEAD^后,再执行git log,观察其变化。
  • 找到提交说明为1的哈希值,执行命令git reset –hard <hash>后,再执行git log,观察其变化。
  • 现在已经回到了旧版本,为了再次回到新版本,执行git reset –hard <hash>,再执行git log,观察其变化。
git@23373387:~/learnGit (master)$ vim README.txt
git@23373387:~/learnGit (master)$ git add README.txt
git@23373387:~/learnGit (master)$ git commit -m "1"
[master e0eb896] 1
 1 file changed, 1 insertion(+), 1 deletion(-)
git@23373387:~/learnGit (master)$ vim README.txt
git@23373387:~/learnGit (master)$ git add README.txt
git@23373387:~/learnGit (master)$ git commit -m "2"
[master 253ed28] 2
 1 file changed, 1 insertion(+), 1 deletion(-)
git@23373387:~/learnGit (master)$ vim README.txt
git@23373387:~/learnGit (master)$ git add README.txt
git@23373387:~/learnGit (master)$ git commit -m "3"
[master 136dd66] 3
 1 file changed, 1 insertion(+), 1 deletion(-)
git@23373387:~/learnGit (master)$ git log
commit 136dd6632f72eb168a6a9ce95d6d8f9f0e509137 (HEAD -> master)
Author: 李昊霖 <23373387@buaa.edu.cn>
Date:   Wed Mar 12 19:57:25 2025 +0800

    3

commit 253ed28d540ba3bc4af73129773e2316ba348202
Author: 李昊霖 <23373387@buaa.edu.cn>
Date:   Wed Mar 12 19:56:56 2025 +0800

    2

commit e0eb89678e8e64c235a12ae2aef580f39e1b914c
Author: 李昊霖 <23373387@buaa.edu.cn>
Date:   Wed Mar 12 19:56:19 2025 +0800

    1
git@23373387:~/learnGit (master)$ git reset --hard HEAD^
HEAD 现在位于 253ed28 2
git@23373387:~/learnGit (master)$ git log
commit 253ed28d540ba3bc4af73129773e2316ba348202 (HEAD -> master)
Author: 李昊霖 <23373387@buaa.edu.cn>
Date:   Wed Mar 12 19:56:56 2025 +0800

    2

commit e0eb89678e8e64c235a12ae2aef580f39e1b914c
Author: 李昊霖 <23373387@buaa.edu.cn>
Date:   Wed Mar 12 19:56:19 2025 +0800

    1
git@23373387:~/learnGit (master)$ git reset --hard e0eb89678e8e64c235a12ae2aef580f39e1b914c
HEAD 现在位于 e0eb896 1
git@23373387:~/learnGit (master)$ git log
commit e0eb89678e8e64c235a12ae2aef580f39e1b914c (HEAD -> master)
Author: 李昊霖 <23373387@buaa.edu.cn>
Date:   Wed Mar 12 19:56:19 2025 +0800

    1
git@23373387:~/learnGit (master)$ git reset --hard 136dd6632f72eb168a6a9ce95d6d8f9f0e509137
HEAD 现在位于 136dd66 3
git@23373387:~/learnGit (master)$ git log
commit 136dd6632f72eb168a6a9ce95d6d8f9f0e509137 (HEAD -> master)
Author: 李昊霖 <23373387@buaa.edu.cn>
Date:   Wed Mar 12 19:57:25 2025 +0800

    3

commit 253ed28d540ba3bc4af73129773e2316ba348202
Author: 李昊霖 <23373387@buaa.edu.cn>
Date:   Wed Mar 12 19:56:56 2025 +0800

    2

commit e0eb89678e8e64c235a12ae2aef580f39e1b914c
Author: 李昊霖 <23373387@buaa.edu.cn>
Date:   Wed Mar 12 19:56:19 2025 +0800

    1
  • 执行 git reset –hard HEAD^ 命令会将当前分支的 HEAD 指针、暂存区和工作目录都重置到上一个提交版本。之后再执行 git log 时,最新的那次提交(即提交说明为 3 的那次提交)不再显示在日志中,日志中显示的最新提交变成了提交说明为 2 的那次提交。这是因为 git reset –hard 会直接丢弃指定版本之后的所有提交记录。
  • 当执行 git reset –hard <提交说明为 1 的哈希值> 后,HEAD 指针、暂存区和工作目录会被重置到提交说明为 1 的那个版本。此时再执行 git log,日志中只会显示提交说明为 1 的这次提交以及它之前的提交,提交说明为 2 和 3 的提交记录都会被隐藏,
  • 执行 git reset –hard <提交说明为 3 的哈希值> 后,HEAD 指针、暂存区和工作目录会被重置到提交说明为 3 的版本。再次执行 git log 时,日志会显示完整的三次提交记录,并且提交说明为 3 的提交会成为最新的提交记录,和最初三次提交完成后查看 git log 的结果是一样的。

Thinking 0.5

执行如下命令, 并查看结果

echo first
echo second > output.txt 
echo third > output.txt 
echo forth >> output.txt
git@23373387:~/learnGit (master)$ echo first
first
git@23373387:~/learnGit (master)$ echo second > output.txt
git@23373387:~/learnGit (master)$ cat output.txt
second
git@23373387:~/learnGit (master)$ echo third > output.txt
git@23373387:~/learnGit (master)$ cat output.txt
third
git@23373387:~/learnGit (master)$ echo forth >> output.txt
git@23373387:~/learnGit (master)$ cat output.txt
third
forth
  • echo first 直接输出 first 到终端
  • echo second > output.txt 将 second 写入 output.txt,覆盖原有内容,此时文件不存在,因此创建并写入。
  • echo third > output.txt 再次将 third 写入 output.txt,覆盖之前的 second。
  • echo forth » output.txt 将 forth 追加到 output.txt 末尾

Thinking 0.6

使用你知道的方法(包括重定向)创建下图内容的文件(文件命名为test),将创建该文件的命令序列保存在command文件中,并将test文件作为批处理文件运行,将 运行结果输出至result文件中。给出command文件和result文件的内容,并对最后的结果进行解释说明(可以从test文件的内容入手). 具体实现的过程中思考下列问题: echo echo Shell Start 与 echo `echo Shell Start` 效果是否有区别; echo echo $c>file1 与echo `echo $c>file` 效果是否有区别。

command:
#!/bin/bash
echo "echo Shell Start..." >> test
echo "echo set a = 1" >> test
echo "a=1" >> test
echo "echo set b = 2" >> test
echo "b=2" >> test
echo "echo set c = a+b" >> test
echo "c=\$[\$a+\$b]" >> test
echo "echo c = \$c" >> test
echo "echo save c to ./file1" >> test
echo "echo \$c>file1" >> test
echo "echo save b to ./file2" >> test
echo "echo \$b>file2" >> test
echo "echo save a to ./file3" >> test
echo "echo \$a>file3" >> test
echo "echo save file1 file2 file3 to file4" >> test
echo "cat file1>file4" >> test
echo "cat file2>>file4" >> test
echo "cat file3>>file4" >> test
echo "echo save file4 to ./result" >> test
echo "cat file4>>result" >> test
result:
Shell Start...
set a = 1
set b = 2
set c = a+b
c = 3
save c to ./file1
save b to ./file2
save a to ./file3
save file1 file2 file3 to file4
save file4 to ./result
3
2
1
git@23373387:~/learnGit (master)$ vim command
git@23373387:~/learnGit (master)$ bash command
git@23373387:~/learnGit (master)$ bash test > result
git@23373387:~/learnGit (master)$ echo echo Shell Start
echo Shell Start
git@23373387:~/learnGit (master)$ echo `echo Shell Start`
Shell Start
git@23373387:~/learnGit (master)$ c=1
git@23373387:~/learnGit (master)$ echo echo $c>file1
git@23373387:~/learnGit (master)$ cat file1
echo 1
git@23373387:~/learnGit (master)$ echo `echo $c>file1`

git@23373387:~/learnGit (master)$ cat file1
1
  • 脚本首先通过echo输出提示信息,然后定义变量a=1、b=2,通过 c=$[$a+$b] 计算 c 的值(a+b=3),接着通过重定向将 a、b、c 的值分别保存到 file1、file2、file3,再将这三个文件内容合并到 file4,最后将 file4 内容追加到 result。
  • echo echo Shell Start 直接输出字符串 echo Shell Start,仅将内容作为普通文本展示,不执行任何命令解析,终端输出”echo Shell Start”。
  • echo `echo Shell Start` 反引号会优先执行内部的echo Shell Start,得到结果 Shell Start,再通过外层echo在终端输出“Shell Start”。
  • echo echo $c>file1 通过$c取出变量c的值,假设为1,而后将字符串“echo 1”写入 file1,由于命令的标准输出被重定向到文件,终端不输出内容。
  • echo `echo $c>file1`有反引号先执行内部的 echo $c>file1,将变量c的值写入file1,由于反引号捕获的是命令的标准输出,但 echo $c>file1 的标准输出被重定向到文件,导致反引号捕获到空字符串,因此输出一个空行。

难点分析

  • 跨目录 Makefile:直接在上级目录编写Makefile时,无法正确找到子目录中的头文件和源文件。为了解决这个问题,一方面,需要通过cd <path> && make 或 make -C <path> 调用子目录的Makefile,另一方面,需要在编译命令中使用 -I 参数指定头文件路径。

  • git 版本回退

    • git checkout -- <file>:从版本库恢复文件到工作区。

    • git reset HEAD <file>:撤销暂存区的修改。

    • git rm --cached <file>:移除暂存区文件但保留工作区。

  • bash 易错点

    • >和»的作用有区别,>用于覆盖写入,»用于追加写入。
    • 小括号、中括号以及某些特殊符号的使用
符号 用途 示例 注意事项
( ) 命令组/数组初始化 (cd dir; pwd) 子shell不影响父环境
$( ) 命令替换 var=$(ls) 推荐替代反引号
` ` 命令替换(同 $()) var=ls 嵌套需转义
(( )) 算术运算/条件判断 ((a = 1 + 2)) 变量可省略 $,运算符无空格
[ ] 基本条件测试 [ -f file ] 空格严格,转义特殊字符
[[ ]] 扩展条件测试(正则、逻辑运算) [[ $str = file* ]] 支持复杂表达式,无需转义通配符
  • 文本处理(grep/sed/awk)

    • grep -E “ERROR WRONG” file:搜索包含指定模式的行。
    • sed ‘s/old/new/g’ file:替换文本中的字符串。

    • awk -F: {print $1} file:把file中的每行文本用冒号分割,打印被分割的第一个字符串。

实验体会

  • 通过实验,从Windows转向Linux环境,我适应了命令行界面的高效操作模式。在过程中,我掌握了常用命令和文件操作;理解了Git的分支和版本管理流程,能够完成代码协作与回滚;同时,掌握Makefile的编写规则,理解自动化编译的依赖关系管理;初步接触Shell脚本,学会通过脚本批量处理任务。

  • 除此之外,我对C语言和汇编的理解相比大一更加深刻,面对编译错误或命令执行异常时,能通过错误信息和文档逐步排查,也能通过gdb等命令行调试工具对错误进行定位,还学会了充分利用官方手册和在线教程(如man命令)搜索解决自己的问题,提升了实践中的问题解决能力。