Linux
Linux
主目录
~
是一个缩写,代表用户的主目录(home),课程所用虚拟机中用户的主目录的路径为/home/co-eda
。双击虚拟机桌面上的“文件管理器”图标,即可进入用户主目录。
在表示文件路径时,我们常用这个缩写,例如 ~/VCS-Example
表示 /home/co-eda/VCS-Example
。
==目录与文件夹==
目录 (directory) 又称文件夹 (folder),这两者一般表示相同的含义。
终端与shell
在虚拟机桌面上双击“终端”图标,即可打开终端。终端是一个==程序==,它使我们能以==文本方式==以计算机交互。
打开终端后,其中将运行一个被称作shell的程序,在终端中的提示文本都是 shell 负责输出的,你的输入也将交由shell处理。shell启动后,会显示co-eda@co-eda ~>
提示,向用户展示一些基本的运行状态信息。
==shell 提示格式==
1 |
|
你可以在shell提示后输入命令,并按回车键,即可执行该命令。例如,执行ls
命令,将列出当前所在目录下的所有文件。
shell分为命令行界面(CLI Shell)和图形用户界面(GUI Shell)
当前目录
shell打印的~
表示当前所在目录。如果从桌面上启动终端,则当前目录默认为用户的主目录。
若想改变当前所在目录,可使用cd <目录名>
命令。例如,想要进入VCS-Example
目录,则可输入cd VCS-Example
,可看到~
变为 ~/VCS-Example
,表示当前目录已经更改。
Linux 中,有两个特殊的目录:.
(一个点)和 ..
(两个点)。一个点表示当前所在目录;两个点表示当前目录的上一级目录。执行cd .
(注意空格)不会有任何作用;执行cd ..
(注意cd和两个点之间的空格)可返回==上一级==目录。
上面的“目录名”是相对路径,即相对于当前目录的路径。cd
命令也可直接到达绝对路径。例如,无论当前目录在何处,输入 cd ~
都可到达用户主目录下。
若觉得使用cd
命令进入目录太麻烦,也可在文件管理器中打开想进入的地方,然后按下F4键,即打开终端并直接进入该目录。
执行命令
shell中,输入命令的格式为 <命令名称> <参数 1> <参数 2> <参数 n> ...
。其中,“命令名称”有两种类型:系统命令和路径命令。
系统命令
系统命令==直接==由==命令名==表示,命令的程序存放于特定的系统程序目录内。例如,cd
和ls
皆为系统命令,我们后面要用到的vcs
也是系统命令。
路径命令
路径命令的格式则为 路径/程序文件名
,程序可以位于任何地方,不一定是系统程序目录。例如,用户主目录中有hello.sh
文件(打开文件管理器即可看到)。在shell中输入~/hello.sh
或./hello.sh
,即可执行这个文件(注意后者只能在用户主目录下执行)。只有特定的文件(例如==脚本==、==可执行文件==)才能被执行,文本文件、Verilog 源代码文件等都是不能执行的。
终止命令
如果一个命令执行太久,你想终止这个命令,可以在终端中按下^Ctrl
+C
,终端会向当前进程发送中断信号,停止其执行。
一些常用的命令
ls
: 查看当前目录下的==所有==文件。命令格式为:ls [选项] [目录]
,常用的选项有-a
(显示隐藏的文件)和-l
(每行只列出一个文件)。文件的组成:文件名、i节点和文件内容——[文件名]->[i节点]->[文件内容],其中i节点中记录了文件权限、所有者、修改日期、长度、存放位置等。
ln file1 file2
:为file1所对应的i节点增加一个文件名file2:,此时,若通过
rm file2
会删除文件名file2,对应i节点和文件内容仍在;再通过rm file1
删除file1,由于没有文件名指向该i节点,系统同时也会删除该i节点及其对应的文件内容。cd
: ==进入==其他目录。/
表示的是linux
文件系统的最顶层根目录,而根目录下包含所有二级目录;~
是当前用户主目录的简写。使用cd ~
回到当前用户主目录。对一般用户,主目录是/home/用户名
;对root用户,主目录是/root
。$
表示当前的用户是普通用户,反之若当前为系统管理员用户,会显示#
。Linux中,.
表示当前目录,..
表示上一级目录,$cd
表示用户登录时所在的位置,因此cd ..
可返回上一级目录,cd -
可跳转到上一次访问的目录。tips:输入文件名或目录名时,可使用
Tab
自动补足全名,有多种补全方案时双击Tab
可显示所可能选项。date
: 查看当前日期时间。cp [选项] <源文件名> <目标文件名>
: 复制(copy
)文件。常用选项**-r
用于递归复制目录及其子目录内的所有内容**。rm [选项] <文件名>
: 删除(remove
)文件。常用选项有:-r
递归删除目录及其内容,删除非空目录必须有此选项,否则无法完成删除;-f
强制删除,不提示用户确认,忽略不存在的目录;-i
逐一提示用户确认每个将要被删除的文件。rm -rf是危险的命令,执行前一定再三确认,它会删除一切文件,包括Linux本身。rm -rf *
或者rm -rf ./*
可以删除当前所在目录的所有文件,而rm -rf /*
删除的是根目录下的所有文件,相当于删除所有的文件,十分危险。mv [选项] 源文件 目标路径
:将源文件(也可是目录)移动为目标路径对应的文件或移动到目标路径中,常用选项为:-v
显示详细操作信息;i
进行交互式操作,覆盖前询问;-u
仅在源文件较新,或目标文件不存在时执行移动操作。可以移动文件同样也可以用来移动目录,还可以重命名文件:也就是把一个文件以不同的名字移动到当前目录下,也就是mv oldname newname
命令可以实现对文件的重命名。mv
相当于移动原有文件,故移动后原位置处没有该文件了。diff [选项] 文件1 文件2
:进行比较的操作,常用选项:-b
不检查空白字符的不同;-B
不检查空行;-q
仅显示有无差异,不显示详细信息。echo <文本>
: 原样==显示==文本。cat <文件名>
: 查看文件内容(catch
?)。head -n <number> <filename>
:可以显示filename
文件的头number
行。head -c <number> <filename>
会显示<filename>
文件的前<number>
个字节的内容。tail -n/-c <number> <filename>
:同理;此外,-f
选项还可以在文件增长时,输出后续添加的内容, 适用于内容不断变化的文件。mkdir [选项] 目录
:创建一个新目录。加上-p
选项可以在当前不存在的子目录下存在目录,实质就是按照文件树格式同时创建两个目录。rmdir [选项] 目录
:删除空目录,只有空的才可被删除。pwd [选项]
:查看当前目录的绝对路径。touch [选项] 文件名
:当文件存在时更新文件的时间戳,当文件不存在时创建新文件。find [路径] <选项>
:在给定路径下递归查找文件,输出符合要求的文件路径,若没给定路径,则在当前目录下查找。常用选项:-name <文件名>
:指定需要查找的文件名。find
命令加上-name
可在当前目录下递归查找符合参数所示文件名的文件,并将文件路径输出到终端上。find
加上-maxdepth <number>
,可以指定递归查找深度。grep [选项] PATTERN FILE
是匹配文件内的内容查找文件和文件中的匹配位置,(PATTERN
是匹配字符串,可以是正则表达式,FILE
是文件或目录的路径)。将会输出匹配PATTERN
的文件和相关的行。常用选项为:-a
:不忽略二进制数据进行搜索;-i
忽略大小写差异;-r
:从目录中递归查找;-n
显示行号,当需要在整个项目目录中查找某个函数名、变量名等特定文本时,grep
将十分有力。fgrep
虽然功能较弱,但处理大文件的能力强,egrep
使用扩展正则表达式。tree [选项] [目录名]
(非Linux发行版预装命令):可以直接输出一个目录下的文件树,常用选项有-a
列出全部文件(包含隐藏文件);-d
只列出目录。man [选项] 命令
(wcis)命令,可以用来查看命令的详细说明手册。echo
:回显指令,其中echo $?
用于显示上一次命令的退出状态。
awk
awk
:强大的文本分析工具,其主要是对于分隔好的列进行操作。
一般使用形式
awk 'program' filename
(program
形式:pattern1{action1} pattern2{action2}
) //模式间为“或”关系,其中pattern
指ed
的正则表达式,逻辑表达式;action
:如print
、printf
(使用方式同正常编程语言,例:awk '{printf("%d:%s\n",NR,$0)}' file
)等
例子:
awk '$1>2{print $1,$3}' my.txt
,该命令格式为awk 'pattern action' file
,pattern
为条件,action
为命令,file
是文件,例子中出现的$n
代表每一行中用空格分隔后的第n项,所以该命令是输出文件my.txt
中所有第一项大于2的那一行的第一项和第三项。可以使用-F
选项来指定分隔符。如awk -F, '{print $2}' my.txt
中就指定了以,
为分隔符。
缺省
awk '/pattern/' file
:显示匹配模式的每一行,功能同grep
awk '{print}'
同cat
记录、字段
- 一行为一条记录,其中
NR
为记录数,其实也就是行号。 - 一个非空字符串为一个字段,使用
$1
、$2
、…标记,$0
代表整行,NF
为字段数 - 例:
awk '{print NR,$0}' file
,显示file并在行首加上行号;ls -l | awk '/^d/{print}'
长格式列出当前目录下的子目录
pattern
请看示例:(在ls -l
的显示中第5个字段是文件的字节大小)
ls -l | awk '$5~/.....*/'
:列出长度超999字节的文件(前四个.
代表四位数,最后一个.
与*
结合形成通配符)ls -l | awk '$5!~/.....*/'
不难理解这就是长度不超过999字节的文件ls -l | awk '$5=="4096"'
通俗易懂吧ls -l | awk 'length($5)>3'
列出长度超过999字节的文件
特殊pattern
:
awk 'BEGIN{初始化动作}'
awk 'END{结束动作}'
例:打印某个文件的行数、单词数和字符数
1 |
|
流程控制
寻找文件中相同的相邻单词
1 |
|
while
使用方式同正常编程习惯,
除了break
、continue
对循环进程的控制,还有next
:下一条记录(也就是下一行),回到awk
程序开始;exit
:跳转至END
模式或结束。
内部变量
FILENAME
:当前输入文件名RS
:输入记录的分隔符(默认为换行符)FS
:输入字段的分隔符(默认为空格、制表符)OFS
输出字段分隔符(默认空格)ORS
输出记录分隔符(默认换行)
内部函数
cos(expr)
求余弦exp(expr)
求自然对数index(s1,s2)
是否字符串s2位于s1中int(expr)
取整split(s,a,c)
按分隔符c
将s
放入a[1]
,a[2]
,……中substr(s,m,n)
求s字串,从第m个字符开始,一共n个字符
数组
例:
1 |
|
进程相关的命令
sleep <time>
:系统等待(秒)ps [-option]
:查看进程,-e
:用来查看所有进程;-f
:用来查看进程详细信息;-t <terminalname>
:显示某个终端启动的进程;-u <username>
:显示某个用户启动的进程。top
:查看进程和占用等kill [option] <pid>
向进程发送信号。kill -l
可以查看能够发送的所有选项。nohup command
注销后仍将运行,使程序运行时不挂起at hh:mm
定时运行某些命令,例如:
$ at hh:mm < commandfile
1
2
3
4
5$ at hh:mm
command1
command2
...
ctrl+Dmkfifo
:在当前目录下创建一个管道文件,可以利用向该文件中写入,读出数据实现进程间的通信。例如,这里以两个不同的
shell
进程举例:1
2
3
4
5
6
7
8
9#shell1
$ mkfifo fi
$ cat < fi #获取管道内的数据,但是此时fi中为空,因此该命令将会一直等待直到另个进程往fi中输入数据
#shell2
$ date > fi #另一个进程往fi中输入数据
#shell1
2025年 04月 14日 星期一 09:09:29 CST #原来等待的cat命令下将输出date的输出,并且结束命令子进程
其他命令
sudo <command>
:以superuser
的身份运行,用来提升安全性。wc <filename>
统计文本文件行数、单词数和字节数。sort
:将标准输入按行排序输出。-k <number>
:是以指定列为关键字排序。-r
:输出逆序
一些命令的小用法
<command1> && <command2>
:前一指令正常退出才执行后一指令。<command> &
:将命令放入后台执行
行编辑器 ed
基本命令
a
从当前行开始添加(可以将输入位置的光标理解为一个指针).
结束添加状态,注:必须在行首输入W
,存盘q
,退出ed
编辑器!
,临时退出ed
,进入shell
显示命令 p
p
,显示当前行- 5,将当前行改为第5行并显示当前行
m,np
,显示第m到n行.
表示当前行,$
表示最后一行- 可以使用相对行,例如:
.,.+3p
、$-5,$p
.
加偏移量时可省略.
,也就是-5
可以表示当前行往前数的第五行
查找
/模式/
,查找下一个匹配模式的行?模式?
,查找上一个匹配模式的行//
重复查找下一个匹配模式的行??
重复查找上一个匹配模式的行- 可使用查找返回的行号
1,/main/p
,显示1到第一次出现main
的行/main/-1,$p
,显示第一次出现main
的行的上一行到最后一行5,?int?d
,删除5到最后一次出现int
的行(这种使用行号的情况下模式查找基准一般定位首行,则//
从首行查找,??
从尾行查找)
插入、删除、撤销
na
,从n
行后添加ni
,从n
行前插入,i、a都以行首.来结束m,nd
删除m到n行u
撤销
替换
替换策略大致与sed
相同(sed
就是ed
的衍生物,当然会很像),
不过还是有细微的差别:s/old/new/g
是**将当前行中每个old
都替换成new
**,而1,$ s/old/new/g
才是将文件中所有old
都替换。
速记符&
,用来代表替换命令s右边的第一个模式:1,$ s/big/very &/g
是将文件中的big都换成very big。
正则表达式
和大多数正则表达式规则基本一致,下介绍我觉得新颖的:
/^$/
空行/./
非空行/^/
任意行
全局命令
命令格式:m,ng/re/cmd
,意即从m行到n行中对于匹配re
模式的行执行命令cmd
,若作用范围为全局,可省略m、n
g/.../p
显示所有包含...
的行g/.../s//rep1g
,将所有...
替换成rep1
v/^$/p
打印所有非空行
移动、复制
m,nmd
,将m到n行移到d行之后m,ntd
,m到n行拷贝到d行后g/^/m0
,将所有输入倒序排列,也就是每行都按顺序移动到第0行之后那么显然原来的第一行将变为最后一行
文本编辑器Vim
通过vim 文件名
,可以通过Vim打开相应的文本并进行文本编辑。
进入后按下I
键进入”插入模式”后可以开始编辑文本内容。完成修改后,按Esc
返回命令模式,再按Shift
+;
进入底线命令模式,在左下角的冒号后输入W
后回车可使文件被保存;再输入q
可关闭文件返回命令行。同时输入wq
可一并完成上述操作。
Vim语法
初级
注意以下命令只在Normal模式下有效
x
——删除当前光标所在的一个字符dd
——剪切p
——粘贴hjkl
:分别对应左下上右:help <command>/:help
:前者可以进入相应指令的帮助文档,后者可以进入总的帮助文档,输入:q
可以退出帮助文档
其他进入插入模式的按键(只能从Normal模式进入插入模式)
a
——在光标后插入,与i
不同,i
是在光标前插入o
——在当前行后插入一个行并进入插入模式O
——在当前行前插入一个行并进入插入模式cw
——“吃掉”当前光标开始的到一个单词结尾的字符后进入插入模式,例如scanf、canf、anf
都可以被一次吃掉。
移动光标的便捷方式
0
——移动到本行的行头^
——移动到本行第一个不是blank字符(空格、Tab、换行等)的字符处$
——移动到本行行尾g——
——移动到本行最后一个不是blank字符的位置。注意——
是-
上的那个,也就是需要用shift
转化。/pattern
:可以用于搜索符合pattern
模式(可以使用正则表达式)的字符串,输入Enter
后进入搜索模式,按n
键可以切换。
拷贝/粘贴
p/P
——粘贴,p是在当前行后一行粘贴,P在当前行之前一行yy
——拷贝当前行
撤销与复原
u
——undo,撤销ctrl+r
——redo,复原
打开/保存/退出/改变文件
:e <path/to/file>
——打开一个文件:saveas <path/to/file>
——另存为<path/to/file>
:x
、ZZ
、:wq
——保存并退出,:x
表示仅在需要时保存。:q!
——退出不保存:qa!
——强行退出所有正在编辑的文件,不论是否修改:bn
、:bp
——可以在用:e xxx
打开多个文件后,使用这两个命令来切换到下一个或上一个文件。
进阶
同样是只能在Normal模式下使用
更好
.
可以用来重复上一个命令。
N<command>
——重复某个命令N次
tips:对于
N.
它将重复上一个命令N次,假如上一次命令自带重复,则无视上一次命令重复的次数,只执行N次。
更强(使光标移动更有效率)
N
G
——到第N行的行头。gg
——到第一行行头,等效于:1
或1G
G
——到最后一行按单词移动:
w
——到下一个单词开头、e
——到写一个单词结尾其中小写代表由字母、数字和下划线组成的单词
而
W
、E
代表由blank字符分隔符组成的单词,也就是**W
、E
认为由空白符分隔开的算一个”单词”**。
5.%
——匹配括号移动,()
、{}
、[]
,需要将光标移动到括号处,按下%直接移动到对应匹配的括号处。
6.*
和#
匹配光标当前所在的单词(变量定义的单词或者非blank字符,注意,非blank字符只有在连续字符串中没有符合变量定义的单词时才被匹配,且可被匹配时会一并被匹配),移动光标到下一个(*)或上一个(#)匹配的单词。
更快
<start position><command><end position>
可以用来进行光标的快速移动。
例如0y$
意味着0
先到行头、y
从此拷贝、$
拷贝到行尾,也就是拷贝该行。
ye
——可以从当前位置拷贝到本单词(**此处的单词是标准的单词,也就是w
**和e
标记的单词)的最后一个字符
当然除了按y
命令会进行拷贝外,下列的命令也会进行拷贝:
d
(删除,一般来说是删除并拷贝当前行和下一行)v
(可视化选择,可以对一个文本块的整体进行操作,例如:可以先高亮选中一部分文本(即可视化),然后再使用d
删除)。可视化的模式有以下三种:
1.
v
进入字符可视化模式,以左右键移动进行的是以字符为单位的文本选择,但上下键移动会将从光标移动到的位置至原位置的所有字符都选上,区别于行选择,当然如果原光标就在行头,那么上下移动可以近似认为就是行选择。 2.
V
进入行可视化模式,此时关注的就只是光标在哪一行了,显然在哪一行,哪一行就全选。 3.
ctrl+V
(注意:这里是大写的V
)进入块可视化模式,有点类似于前两种模式的结合版,也就是从初始光标那行开始算起,上下键移动就是增加被选择的行,但是依靠左右键来决定每行从左至右由初始光标在的位置选择到第几个字符(每一个被选择的行被选择的字符是行对齐的)。此外,可以通过
ctrl+Q
来从行或字符可视化模式切换到块可视化模式(注意只能单向切换,块可视化模式下再按ctrl+Q
是退出块可视化了)。可视化下进行编辑,
d
删除高亮文本,D
删除一整行,即使这一行中只有部分文本高亮。同理,y
复制高亮文本,Y
复制整行。块可视化模式下,使用
c
将删除高亮文本并进入插入模式,此后输入文本并点击Esc
返回后,输入的文本将插入到原来块选中的每一行的字符区间上;使用C
将删除高亮文本至末尾的所有字符并进入插入模式,其余同c
。~
可将高亮文本中的字母进行大小写转换;>
:分为两种情况:不在可视化模式中,将为当前行和下一行增加缩进,也就是在行首加一个Tab
;在可视化模式下,注意这里行/字符可视化模式同块可视化模式略有不同,前者仅为光标所在行增加缩进,而后者将为光标所在的地方开始增加缩进,也就是在每一行的光标对齐处增加一个Tab'
,但是上诉三种方式在增加完缩进后都会退出可视化模式。<
:用法同>
,但功能是减少缩进。=
会自动给缩进J
:两种情况:不在可视化模式中,将当前行和下一行合并为一行并且以空格分隔开;在可视化模式中,哪种可视化模式都一样,将所有有高亮部分的行以空格分隔合并成一行并退出可视化模式。gJ
:用法同J
,只不过分隔的不是空格而是Tab
。g?
:两种情况:不在可视化模式中,将依据rot 13算法,对当前行和下一行进行加密,再按一次即可解密;在可视化模式中,即对高亮文本进行加密并退出可视化。可视化模式下,按下
:
可对选定范围进行操作,例如:选中后执行:write xxx
会将选中的文本写入xxx
文件中,若该文件已经存在,则使用:write! xxx
可以强制覆盖写入;gU
:将选中文本中的字母变为大写gu
:将选中文本变小写
vim超能力
在当前行进行移动
0
:到行头^
:到本行第一个非空白符字符处$
:到行尾g——
:到本行最后一个不为空白符字符处fx
:到本行下一个为x
字符的位置tx
:到本行下一个为x
字符的前一个字符处3fx
:在当前行查找从当前光标下一个字符开始第三个出现的x
字符位置处F
、T
用法同f
、t
类似,只不过方向相反- 一个可能很有用的命令
dt"
:删除所有的内容直到遇到双引号"
区域选择
可视化模式下,命令格式为:<action>a<object>
和<action>i<object>
。
action
可为任意命令,如d
、y
、v
等object
可以是:w
一个单词、W
一个以空格分隔的单词、s
一个句子、p
一个段落,也可以是"、
、'、
、)、
、]。
、}、
等
例子:有一个字符串(map(+)("foo"))
,且光标在第一个o
处,则
vi"
:会选择foo
va"
:会选择"foo"
vi)
:选择"foo"
va)
:选择("foo")
v2i)
:选择map(+)("foo")
v2a)
:选择(map(+)("foo"))
自动补齐
在插入模式下,在输入完一个词的开头的前提下,按ctrl+p
可以开启选择可能的输出结果的序列。
宏录制:qa
操作序列q
、@a
、@@
qa
会将操作记录在寄存器a
中- 这样一来
@a
会返回被录制的宏 @@
用来返回最新录制的宏
一个例子
在光标所在行只有
1
中,输入如下命令:
qa(开始录制)->Y(拷贝本行)->p(在下一行粘贴)-><ctrl+a>(将数自增)->q(结束录制)->@a(按顺序重复被a录制的命令)->100@@(按顺序重复最新录制进寄存器的命令)
分屏
:split
和vsplit
,前者创建分屏,后者创建垂直分屏
常用快捷键
ctrl+C
:终止当前程序的执行。
ctrl+Z
:挂起当前程序,放到后台,挂起程序后会显示编号,想要恢复可使用fg [job_spec]
即可,job_spec
为挂起编号,不输入时默认为最近挂起进程。
ctrl+D
:终止输入,若正使用shell,则退出当前shell,**在标准输入中相当于输入了一个EOF
**。
ctrl+L
:清屏,相当于命令clear
。
ctrl+S
:暂停该终端,使用ctrl+Q
即可使终端再次运行。
脚本
有时,我们需要执行一些固定的命令,每次都输入这些命令会比较麻烦。这时,我们需要使用“脚本” (script) 来简化操作。脚本的基本功能就是将许多命令==汇整==写在一起,让使用者能够一键进行较为复杂的动作。
我们可以像运行程序一样运行脚本。例如,上面提到的hello.sh
就是一个脚本,在shell中输入~/hello.sh
,就可以运行。如果上述方法不能正常运行,也可使用sh {name}.sh
来运行脚本。
hello.sh
:
1 |
|
脚本的实质为==文本文件==。hello.sh
的第一行为[shebang](关于 Bash 脚本中 Shebang 的趣事 - 知乎 (zhihu.com))(用来指定脚本的解释器路径),用于指定解释器为 bash,所有的 bash 脚本都需要带有这一行,否则无法正常执行。第二行为空行。第三行为注释。以#
开头,类似python的写法。最后一行,脚本使用echo
命令,完成一行输出。
如果使用Sublime Text编写脚本并尝试运行,系统会提示 fish: The file './1.sh' is not executable by this user
。这是因为我们没有给脚本文件赋予执行权限。在用户主目录下运行ls
命令,会发现hello.sh
呈绿色加粗(表示有执行权限),而xxx.sh
(xxx.sh为之前尝试运行的文件的文件名) 则呈现黑色(表示该文件为普通文件,无执行权限)。
要赋予执行权限,只需运行chmod +x xxx.sh
即可。赋予后,脚本就可以直接执行了。再次运行ls
命令,发现xxx.sh
也已经是绿色加粗了。
Linux中的shell脚本
脚本文件的文件名一般都以.sh
结尾,可以通过./文件名
(此处文件名包含.sh
)运行。(一般是使用bash xxx.sh
来运行脚本的,想要使用./xxx.sh
来运行需要先为脚本添加权限。)
需要注意:被执行脚本文件有“执行”权限,Linux中,每个文件对于拥有者、用户组和其他用户都有”读”、“写”、“执行”的权限,使用
touch
命令创建的文件默认没有“执行”权限的,要手动添加:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
chmod +x 文件名
#chmod的语法:
#chmod 权限设定字串 文件...
#权限设定字串格式: [ugoa...][[+-=][rwxX]...][,...]
#其中,u表示该文件的拥有者,g表示与该文件拥有者属于同一个群组,o表示其他以外的人,a表示三者皆是。
# +表示增加权限、-是取消、=表示唯一设定权限
# r表示可读取、w表示可写入、x表示可执行、X表示只有当该文件是个子目录或该文件已被设定过为可执行
#此外chmod也可以用数字来表示权限,格式为:
chmod ugo <file>
#ugo分别为三位的二进制数在十进制下的数值,从高到低分别表示rwx的权限是否打开
#示例:
#为run.sh的拥有者添加执行权限
chmod u+x run.sh
#修改run.sh权限为 rwxr-xr-x(对应二进制111(b)、101(b),也就是有权限代表二进制的1,没有代表0,对应翻译为十进制数)
chmod 755 run.sh
#移除所有人对run.sh的写权限
chmod -w run.sh
shell元字符集
- >、>>、<、<<、|、*(匹配文件名中任意字符)、?、ccc、;(命令结束符,用于连接两个有顺序要求的命令)、&(后台命令结束符,将命令挂到后台)、
...
(将命令…运行的结果返回)、(…)(在子shell中运行…命令)
test命令
主要用于if、while、until命令中的条件判断,即判断文件类型或表达式是否为真
语法:
test -option file
~ -e file
//判断file是否存在~ -b file
//判断是否存在且为块设备文件~ -c file
//判断存在且为字符设备文件~ -d file
//存在且为目录文件~ -f file
//存在且为普通文件
test expression
~ e1
//判断e1为真~ ! e1
//e1为假~ e1 -a e2
//都为真~ e1 -o e2
//都为假~ f1 -nt f2
//f1比f2新~ f1 -ot f2
//f1比f2旧
test -option string
~ -n str
//str非空~ -z str
//为空
shell内部变量
- $# 命令行参数个数
- $* 命令行参数集合
- $@ 命令行参数集合 //与$*略有不同
- $? 上一条命令的返回值
- $$ 当前shell的进程号
- $! 最后一个后台命令的进程号
- $HOME、$PATH、$PS1、$PS2
其他命令
- break
- continue
- exit n 终止shell程序,n为返回值
trap
设置中断处理命令,例如:trap 'rm -f tmpfile; exit 1' 1 2 15
实例 myWhich
which
命令可以返回某个命令的可执行文件所在目录
1 |
|
bash shell语法
初学者必打代码
第一行一定是要指定脚本的解释器路径:如:#!/bin/bash
,其中#!
称为Shebang,程序加载器会将文件中Sheband后的内容作为脚本文件的解释器。
变量
作为弱类型语言,定义变量时无需指定类型,采用:var_name=value
方式定义变量,注意等号两边不能有空格。
通过使用$var_name
获取变量的值,建议变量名左右加上{
来帮助解释器识别变量边界。这里加上花括号是指在引用变量的时候,创建变量的时候不建议使用。
通过set
命令可以重置位置参数,不过不可以重置$0,其为命令名。
通过shift
命令可左移位置参数,但不可移动参数$0,相当于用set
命令把右边的参数重置到左边去。
1 |
|
数组
1 |
|
脚本参数——特殊的变量
参数在shell脚本中体现为特殊的变量,运行脚本语句中,一个参数在脚本中都是一个字符串常量,按顺序一个参数映射到相应的变量名上。
例如:
1 |
|
因而在执行脚本(采用./(name).sh
的方式执行,sh (name).sh
后加参数实测会出现报错)时可以输入由空格分开的两个参数,根据顺序,前者对应$1
,后者对应$2
.
只有在双引号内才能正确的进行传参,若为单引号,则会输出原内容,并不会进行参数的传递。传入的变量若作为文件名,建议一定要加上双引号修饰,避免造成歧义。例如:grep -n "$2" "$1" | awk -F: '{print $1}' > "$3"
,其中双引号内的变量分别是$1:file、$2:int、$3:result
其他的特殊变量:
$#
传递参数个数,即按空格分割开的参数的个数。$*
一个字符串,内容为传递的全部参数。也就是会将脚本输入时的所有参数打包成一个字符串当作参数。
条件与循环
1 |
|
注意等号前后不能有空格,左中括号后和右中括号前一定要有空格,例如:
1 |
|
函数
定义:
1 |
|
第N个参数在函数体内使用$N
来获取,不需在函数定义开头声明。
注意:N>=10时,要用
${N}
获取参数,否则$
只会带一位数字。
若函数有返回值,则在函数调用后需要使用$?
获取返回值。
例:
1 |
|
用命令编辑和输出文本——sed的使用
1 |
|
注意只有加入了
-i
选项才能对源文件进行修改。
重定向
在Linux中使用重定向将命令的输出写到文件中。
Linux中的三种流:由0表示的
stdin
(标准输入)、由1表示的stdout
(标准输出)、由2表示的stderr
(标准错误)
一般情况下,这些流使用的设备是控制台,即可在控制台上看到命令的输出。在命令后使用>
可将输出重定向。
例:$ ls / > lsoutput.txt
可将根目录下的文件名输出到当前目录的lsoutput.txt
文件中,覆盖文件的原有内容,通过>>
可以实现在文件后追加命令的输出,并不会覆盖掉原来的内容,可以理解为在原内容基础上继续添加内容。
实际上,>
是1>
的简写,对应输出的是标准输出。
如果想要重定向标准错误,可以使用2>
.例如可以通过gcc 2> gccerr.txt
在gccerr.txt
文件中观察到gcc
输出的编译错误。
使用<
,代表标准输入重定向。
而<<str
是即时文件读入,直到str结束,可用于在shell程序中创建文件:
例:
1 |
|
cat > $1 << end #将以下的内容输出到$1中直到遇到了end字符
hello world!
end
1
2
3
$ sh mkafile ttt
$ cat ttt
# hello world!
管道
|
可对命令进行连接:
command1 | command2 | ……
作用是将command1
的输出传给command2
的输入,以此类推。
例:
cat hello.txt | grep "Hello"
cat
命令将文件内容输出到标准输出,grep
命令从标准输入读取文本,可将hello.txt
文件输出,内容传入grep
命令,其在这些内容中查找Hello
字符串。
$()、``
$()
用于隔离并执行命令,并将输出替换至原处,此外**``**也有同样的效果。
例如:
1 |
|
或许可以这样来理解$(command)
:1.bash
会启动一个子进程来执行command
。2.bash
执行命令command
时,会将'
、"
所包裹的内容当作一个command arg/token
。例如echo $(‘pwd')
会输出执行pwd
命令后的结果。
此外,'
和"
包裹的命令在交互终端中是可以直接使用的。
在交互终端中*
表示当前目录下所有文件和子目录的文件名和目录名的集合。
1 |
|
(())
(())
用于算术表达式,
例如:
1 |
|
[]
[]
用于判断条件是否成立。至于为什么中括号中左右都需要有空格,那是因为我们写在判断条件时实际上是将中括号内的东东**作为参数传给可执行程序[**。[
在/bin
中。
[[]]
同样用于判断条件,但比[]
功能更加丰富。例如在[[]]
中可直接使用逻辑运算:[[ $a -gt 1 && $a -lt 100 ]]
。注意:同样也要加空格。
智能补全与历史联想
如果每次cd
或执行其他命令都要输入全名,未免有些麻烦。在shell下,按Tab键可以使用智能补全功能,根据当前目录下的对象名称进行补全。例如,要想进入VCS-Example
目录,只需输入 cd V
,然后按下键盘的Tab键,shell会自动帮你补全剩下的字符。
虚拟机中的shell还提供了历史记录联想功能。输入命令的一部分后,如果你以前执行过类似命令,shell会以灰色显示联想出的部分。例如,如果你以前执行过cd VCS-Example
,在输入cd VC
后,终端会显示cd VCS-Example
,灰色部分即为联想。这时,按下键盘上的==右方向键==,即可确认联想部分。注意按回车后,灰色的部分不会执行,需要确认后才能执行。若有多个联想,可用==上下方向键==来选择;如果联想的内容只有一部分是你想要的,则可用 ==Alt+右方向键==来逐单词确认。
不同shell之间的差异
Debian、Ubuntu、CentOS 等 Linux 发行版默认的shell是bash,而本课程提供的虚拟机映像的默认shell是fish。
fish的功能更加强大易用,但它与使用更广泛的 POSIX 兼容终端(如 bash)的行为不尽相同。以bash为例,fish和bash在命令替换语法、变量设置语法、流程控制语法等诸多方面上有显著不同。在尝试运行来源于网络的shell命令时,需要注意相关语法差异。
关于fish和bash的详细区别,可以阅读官方文档:Fish for bash users。
你也可以在fish中启动bash或者其他shell,以求正确地执行来源于网络的shell命令。
关于在脚本文件中指定其执行shell,参考:Shebang。
Linux中的实用工具
GCC
(GNU Compiler Collection,GNU编辑器套件),包含了著名的C语言编译器gcc。
gcc使用格式:gcc [选项] 源代码文件
用来编译源代码文件。再没有进行其余选项的修饰下,经由gcc编译产生的可执行文件名均为其默认的a.out
文件名。通过运行./a.out
即可运行该可执行文件。**./
是当前目录下的意思,Linux会在当前目录下查找可执行文件,若没有,则Linux会在“系统PATH”中寻找,而a.out
不在系统PATH中,因此执行时会报错**。
若想要同时编译多个文件,可以使用如下命令:gcc testfun.c test.c -o test
(可直接将多个文件编译连接)或gcc -c testfun.c && gcc -c test.c && gcc testfun.o test.o -o test
(先用-c
将每个文件单独编译成.o
文件,再用-o
将.o
文件链接)
1 |
|
make & Makefile
在较大的项目中,make工具可以将这些文件编译链接成可执行文件,而进行编译和链接的操作是经由Makefile
来指导的。make工具根据时间戳自动判断项目的哪些部分要重新编译,每次只编译必要部分。
1.不使用make工具,可以使用
1 |
|
来对helloworld.c进行编译,其中-o
是为编译产生的可执行文件命名(如helloworld)。
2.使用make工具,需要在当前目录下创建并编辑Makefile文件,文件名就为Makefile
。
基本格式为:
1 |
|
若Make命令运行时没有指定目标,默认会执行Makefile文件的第一个目标。
每行命令在一个单独的shell中运行,之间没有继承关系,可以近似的理解为不同行的命令会同时运行,解决方法有:
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]"
Makefile
中书写的显示规则告诉make工具文件间的依赖关系:若想要创建target
,先准备好dependencies
,再执行command
中的命令,得到target
。在这之后只需在shell中输入make target
即可执行相应命令、生成相应目标。
之后运行make target
或make
即可产生相应的可执行文件。
make语法
注释
#代表注释
回声
一般情况下,用make
运行目标(命令)时会打印每条命令,然后再执行,也就是回声(echoing),包括目标里包含的注释,而在命令或注释前加上@
就可以关闭回声,由于构建时需要了解当前在执行哪条命令,所有常只在注释和纯显示的echo
命令前加上@
。
通配符
用来指定一组符合条件的文件名(正则表达式)。与Bash的一致,主要有*
、?
、[...]
,其中*.o
表示所有后缀名为o的文件。
模式匹配
实则是对文件名进行类似正则表达运算的匹配,主要的匹配符是%
,旨在一条规则完成构建。例如:若当前目录下有f1.c
和f2.C
两个源码文件,将它们编译为对应得对象文件:
1 |
|
变量和赋值符
可以使用=
自定义变量,例:
1 |
|
调用Shell变量需要在$前再加一个$。
可以变量给变量传递值吗?当然可以。但是为了避免一些传递的麻烦,Makefile提供了四种赋值运算符(=
、:=
、?=
、+=
):
1 |
|
内置变量
如,$(CC)指向当前使用的编译器,$(MAKE)指向当前使用的Make工具。
自动变量
$@
指代当前目标(this?)即Make命令当前构建的目标,如make foo
的$@指代foo。
$<
指代第一个前置条件,若规则为 t: p1 p2
,则$<指代p1.
$?
指代比目标更新的所有前置条件,之间以空格分隔,如,规则t: p1 p2
,中若p2时间戳比t新,则$?指代p2.
$^
指代所有前置条件,之间以空格分隔。
$*
指代匹配符%匹配的部分,如%匹配f1.txt
中的f1
,则$*
指代f1
。
$(@D)和$(@F)
前者指向**$@**的目录名(directory),后者指向文件名(file),$@
是当前目标,如若$@
是src/input.c
,则前者指代src
,而后者指代input.c
。
$(<D)和$(<F)
分别指代$<
的目录名和文件名。
判断与循环
语法同bash。
函数
格式为:
1 |
|
此外,还有内置函数。
shell函数
执行shell命令:
1 |
|
wildcard函数
替换Bash的通配符。
1 |
|
subst函数
进行文本替换:
1 |
|
一个栗子:
1 |
|
patsubst函数
用于模式匹配的替换:
1 |
|
替换后缀名
格式为:变量名+冒号+后缀名替换规则,实际是patsubst函数的简写。
例如:
1 |
|
提升效率的变量使用方法
示例
1 |
|
如何在嵌套目录中进行编译make呢?
可以使用$(MAKE)
并配合-C
选项来进入相应的目录进行make
编译
例:
1 |
|
Tips
- 开头最好写上
.PHONY xx
,例如:.PHONY: clean
避免同名文件冲突。
ctags
方便代码阅读的工具,起到代码跳转功能。
使用前在~/.vimrc
文件中添加:
1 |
|
使用实例:
在hello.c
中为:
1 |
|
在ctags_test.h
中输入:
1 |
|
再执行命令ctags -R *
会在目录下发现ctags为我们创建的符号索引文件tags
,之后在c文件中光标移动到结构体相应变量中按下ctrl+]
,即可跳转到其定义处,按ctrl+o
可返回原来的位置,其实只要是在一个文件中使用另一个文件里定义的==东东==都可以通过ctags进行移动。此外,vim中按:
进入底线命令模式后输入tag xxx
也可跳转到xxx定义的文件的中xxx的位置处。
tmux
实现终端窗口和进程分离,在窗口中同时显示多个进程的运行。
输入tmux
进入tmux的新会话。
通过以下快捷键可以对tmux
进行操作。
窗格操作
ctrl + B
(同时按下ctrl+B
后松开这两个键,紧接着输入%
,可以将窗口左右分屏。
ctrl + B
同上松开后再输入"
即shift + ‘
,将窗口上下分屏。
ctrl + B
再输入O
可以依次切换当前窗口下的各个窗格
ctrl + B
前面松开后紧接着(上下左右按键)可以根据按键方向切换到某个窗格。
ctrl + B
+space
,切换窗格布局(上下变左右,左右同理)
ctrl + B + Z
最大化当前窗格
ctrl + B
+ X
,关闭当前正在使用的窗格。
ctrl + B
+ D
分离当前会话,回到shell终端环境,程序仍保持在tmux会话中的状态。
窗口操作
ctrl + B C
:创建后多一个窗口
~ P
切换到上一个窗口
~ N
切换到下一个
~ num
切换到num
号窗口
~ W
列出当前会话(session
)所有窗口,可通过上、下键切换
~ &
关闭当前窗口,会有提示。
会话操作
tmux new -s 会话名
新建会话Ctrl+B D
退出会话,回到 shell 的终端环境tmux ls
终端环境查看会话列表tmux a -t 会话名
从终端环境进入会话tmux kill-session -t 会话名
销毁会话
如何恢复会话呢?先使用tmux ls
查看当前有哪些会话,记住会话名(是冒号左边的内容,默认情况下是一个数字),使用tmux a -t 会话名
。
图形界面与系统管理
特殊管理
激活超级用户(root)
使用sudo
(super user do)提升权限,sudo passwd root
:更改root用户口令;sudo reboot
:重启系统
更改软件源
/etc/apt/sources.list
是一个记录用于系统升级的软件源地址的文本,可修改为更优的软件源。apt-get update
:使软件园生效,下载更新列表信息。
网络配置
IP地址、子网掩码、默认网关
域名服务器DNS
网络应用
创建WebServer
apt-get install apache2
共享文件
apt-get install samba
用户管理
sudo
命令。
用户账号管理
命令:useradd
、adduser
、userdel
、usermod
、passwd
,增删用户,修改用户权限、密码。
组管理
groupadd
、addgroup
、groupdel
、groupmod
和gpasswd
,类似用户账户管理。
系统数据文件
/etc/passwd
、/etc/shadow
、/etc/group
磁盘管理
硬盘设备文件:/dev/fd[01]
、/dev/hd[abcd]
(IDE硬盘)、/dev/sd[abcd]
(SCSI硬盘)、/dev/cdrom
(光盘)。
硬盘必须分区和格式化后才可使用,分区后,每个分区对应设备名为”设备名”[1256],例如:/dev/sda1
表示第一块SCSI硬盘的第一个分区。
一块硬盘最多分4分区,要更多区时,可分一个扩展分区,然后再分为若干逻辑分区。
使用fdisk
命令来管理硬盘分区,例:fdisk /dev/sdb
是对第二块SCSI硬盘进行分区管理。
格式化分区就是在创建文件系统,mkfs <分区名>
(格式化)、mkfs -t msdos <分区名>
:指定了文件格式,默认文件格式为ext2。
mount <分区名> <path>
:将某硬盘分区挂载在某个空目录下,使用文件系统。
umount <分区名或path>
:将某硬盘分区和挂载点脱钩,卸载文件系统。
df
:查看分区挂载情况。
虚拟机中的文件题目快速提交工具
在虚拟机中内置了co-submit
工具,这个工具可以帮你更方便地提交“文件上传”类型的题目。
要使用这个工具提交题目,首先需在题目页面中记下要提交的题号(题号位于题目名称的右侧),例如图中题目的题号为 712-23
。
在虚拟机中完成题目后,打开“终端”,使用cd
命令切换到答案文件所在地,然后运行co-submit 题号 文件或目录名
即可提交该题目。首次提交的时候会提示登录,输入自己的用户名和密码即可。

Verilog题目可能需要提交多个.v文件。此时可以在参数列表中指定多个文件名,例如co-submit 233-23 aaa.v bbb.v
;也可以指定通配符,例如co-submit 233-23 *.v
;还可以提交一整个目录,例如co-submit 233-23 directory-name
。工具会==自动对多个文件进行压缩==,无需手动压缩。