操作系统 Lab0:git与shell
一、实验思考题
thinking 0.1
- 不一样,第一次add前时README.md属于尚未跟踪文件;第二次修改后的文件属于工作区未暂存以备提交的变更。
- 不同的原因:未跟踪文件不存在于.git对象库中,而修改后未提交的文件存在一份修改前的文件在.git的对象库。
thinking 0.2
1.add the file :$ git add
$ git commit
2.stage the file :$ git add
3.commit :$ git commit
thinking 0.3
1.恢复工作区的printf.c :$ git checkout -- printf.c
2.$ git rm --cached printf.c
后,恢复暂存区文件:
$ git reset HEAD printf.c
$ git checkout -- printf.c
3.删除暂存区文件,同时保留本地:git rm --cached Tucao.txt
thinking 0.4
命令与结果
- 找到提交说明为1的哈希值,使用 git reset –hard
,再使用git log,2和3的版本库消失了。 - 找到记录下的提交说明为3的哈希值,git reset –hard <Hash-code> ,再使用git log,123版本库均存在,但恢复的2和3的内容均回退为1的内容。
思考
git reset –hard <Hash-code>的版本回退问题: - HEAD类似指针,各提交版本类似链表。
git reset
回退到某个版本,只回退了commit信息,不会更改对象库内存储的文件对象.git reset --hard
无法恢复,指在本地的源码变为回退版本库的内容,撤销的commit的更改被抹除。- 实际上后退的版本库的文件对象仍存在于对象库中,
--hard
无法恢复指的是文件内容被改写,即被回退到的版本库的文件内容覆盖。
thinking 0.5
1.1克隆时所有分支均被克隆。(正确)
- 首先,git clone时若未使用git clone -b说明HEAD指向的分支,默认HEAD为master
- 第一次git clone时,HEAD指向master,此时git clone共12个文件
- 其后未对master进行修改,只对test1 test2分支进行修改
- 再次git clone -b master时,git clone共16个文件,说明克隆时所有分支均被克隆
1.2只有HEAD指向的分支被检出。(正确)
- git clone -b master,git branch后只有master分支
- git clone -b test1,git branch后只有test1分支
2.克隆出的工作区中执行 git log、git status、git checkout、git commit等操作不会去访问远程版本库。(正确)
- 这四项命令均针对于clone时的版本快照,不会与远程库同步
- 只有git pull后才会实现本地依照更新的远程库进行更新的步骤
- 具体实现为:git clone后,在另外的本地库进行对远程库的修改,再回到刚刚git clone的本地库中执行git log等命令时,不会同步远程库的更新
3.克隆时只有远程版本库HEAD指向的分支被克隆。(错误,见1.1)
4.克隆后工作区的默认分支处于master分支。(见1.2)
- 若使用git clone,工作区默认分支处于master分支
- 若使用git clone -b branch,工作区默认分支处于branch分支
thinking 0.6
echo third > output.txt
> 覆盖echo forth >> output.txt
>> 追加
thinking 0.7
command
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
test
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
result
3
2
1
结果解释
- save可以将变量和文件的内容重定向至文件
问题1
echo echo Shell Start
echo 'echo Shell Start'
# 显示echo Shell Start
echo `echo Shell Start`
# 显示``反引号内命令的执行结果Shell Start
问题2
- echo命令无引号时,识别首尾的”echo …无变量无转义字符串… > file”模式,重定向原字符串到文件,且无转移无变量;终端无输出
- echo命令有单引号时,会把单引号的内容以无转义无变量的形式输出
- echo命令有反引号时,会把反引号的内容作为命令执行,把命令的输出结果使用echo输出
testbash.sh
```shell
echo Shell Start…
echo set a = 1
a=1
echo set b = 2
b=2
echo set c = a+b
c=$[$a+$b]
echo c = $c
rm file1
echo echo $c>file1
echo ‘echo $c>>file1’
echoecho \$c>>file1
echo echo $c>file1
echo echo $c>file1
echo echo \$c>file1
file1
echo 3
echo $c
echo \3
echo ‘echo $c>>file1’
单引号:除了单引号,全部为字面意义
//变量引用、算术运算和子命令,都失效了
//所以如果单引号之中,还要使用单引号,不能使用转义,需要在外层的单引号前面加上一个美元符号($),然后再对里层的单引号转义。
//更合理的方法是改在双引号之中使用单引号。
//echo $’it's’
echo “echo $c>>file1”
echo “echo $c>>file1”
echo “echo \$c>>file1”
终端
echo 3>>file1
echo $c>>file1
echo \3>>file1
//三个特殊字符除外:美元符号($)、反引号(`)和反斜杠(\)。这三个字符在双引号之中,依然有特殊含义,会被 Bash 自动扩展。
//美元符号用来引用变量,反引号则是执行子命令。
//换行符在双引号之中,会失去特殊含义,Bash 不再将其解释为命令的结束,只是作为普通的换行符。所以可以利用双引号,在命令行输入多行文本。
//双引号的另一个常见的使用场合是,文件名包含空格。这时就必须使用双引号,将文件名放在里面
musel@musel-virtual-machine:~$ echo it’s
s’
its
s
#### file1
> echo $c
echo echo \$c>file1 的输出
> 3
echo \`echo \$c>>file1` 的输出
#### out
> Shell Start...
> set a = 1
> set b = 2
> set c = a+b
> c = 3
> **echo \$c>>file1**
> \# echo 'echo \$c>>file1' 的输出
>
> \# echo \`echo \$c>>file1` 输出一个回车
# 二、实验难点
## 1.sed命令的-n 和 -i模式 ——显示与修改的区别
### 不使用 -i 参数时,'d''s'相关的删除、替换等工作都是对于终端显示或重定向的,不修改源文件
- `sed '3p' txt` 首先,sed的命令是按行遍历的,则此条命令在遍历输出txt时,会额外在遍历到第三行时输出第三行
- `sed -n '3p' txt` 在遍历到第三行时输出第三行,输出仅一行
- `sed '3d' txt` 输出源文件,不输出第三行
- `sed -n '3d' txt` -n此时只输出操作行,操作行又被删去,所以无输出
### 使用 -i 参数,对源文件修改
- `sed -i 's/str1/str2/g' txt` 修改,无显示
- `sed -n 's/str1/str2/g' txt` 无显示
- `sed 's/str1/str2/g' txt` 显示替换后的文件
- `sed '/str/d' txt` 不显示包含str的行
- `sed -n '/str/p' txt` 显示包含str的行
- `sed -n '/aaa/p' txt | sed 's/aaa/bbb/g'` 显示替换后的行
## 2.gcc链接库文件 两种命令的区别
- `-include filename`功能相当于在代码中使用`#include<filename>`,代码中不能出现`#include<filename>`
- 对于代码中出现`#include<filename>`的情况,需要使用`-Ipath`链接库
## 3.单引号与双引号的区别
- 单引号无法引用变量,仅作为字符串解析
- 双引号可以引用变量
- `sed -i 's/str1/str2/g' txt`,如果str1的位置是`$1`**参数传递**,需要改成**双引号**
## 4.makefile用法
- 只使用外部Makefile
```makefile
fibo: code/main.c code/fibo.c # 依赖文件
gcc -c code/main.c code/fibo.c -I./include # 仅列出头文件所在目录即可
mv fibo.o ./code/fibo.o # -c只编译不链接
mv main.o ./code/main.o # 在当前makefile文件目录下生成
gcc -o fibo code/main.o code/fibo.o -I./include
clean:
rm ./code/fibo.o
rm ./code/main.o
- 外层调用内层Makefile
外层:
内层:new:./code/main.c ./code/main.c cd ./code && make # 同时执行两条命令 clean: cd ./code && make clean
new:main.c fibo.c gcc -c main.c fibo.c -I../include gcc main.o fibo.o -o ../fibo clean: rm main.o rm fibo.o
三、体会与感想
- linux指令以及众多工具的命令过于简洁与灵活,部分资料仅有各种参数的说明而没有使用实例的情况下,较难理解掌握,链接资料读起来也难度不一,经常出现一行代码修改多次仍达不到想要的效果,或对于使用什么样的指令和参数无从下手。
- 在虚拟机和git的环境下多尝试使用命令行实践,而不是字面意义上试图看懂各种复杂命令与参数,是上手更快的一种方式。
- thinking的引导是很有启发的,在使用实例的复现和探索中,对于git和命令行的掌握更加深入。
四、指导书反馈
- 关于指导书’课程>初识操作系统>Git 专栏–轻松维护和提交代码>Git文件状态’中,下图类似输入命令与文件状态的状态机,更为清晰。
- 原图中出现的’add the file’(实际代表
git add & git commit
)容易与git add
造成理解上的混淆
- 未跟踪
- 表示没有跟踪(add)某个文件的变化,使用git add即可跟踪文件
- 工作区文件,未添加对象,易失
- 未修改
- 表示某文件在跟踪后一直没有改动过或者改动已经被提交
- 工作区与对象库文件一致,且暂存区和版本库的目录树均指向此文件
- 已修改
- 表示修改了某个文件,但还没有加入(add)到暂存区中
- 工作区和对象库不一致,暂存区和版本库的目录树均指向此对象库文件
- 已暂存
- makefile与gcc结合实现多文件链接编译中,对于makefile可以如何更加灵活地使用非常模糊。