以下是计算机专业大二第一学期计算机系统2A的前半部分内容,也就是操作系统部分。本笔记几乎涵盖了PPT中的所有Linux指令,并标注了用法。部分地方可能存在错误,欢迎在评论区指出。
学Bash最好的方式就是把每个指令都自己敲一遍,看看效果。顺带一提,这个项目的评分标准非常看重处理BUG,要把会出BUG的地方全部考虑到并处理掉。
一.文件操作
1. 文件夹
pwd 显示当前工作目录
cd或cd ~ 将工作目录移至用户的主目录(/home/username)
cd / 将工作目录移至根目录
cd .. 将工作目录移至上级目录
cd 路径 将工作目录移至该路径
路径分为绝对路径和相对路径。
ls 文件夹名 列出该文件夹下的所有文件
ls -l 文件夹名 列出该文件夹下所有文件的详细信息
mkdir 文件夹名 创建一个文件夹
rmdir 文件夹名 如果该文件夹为空文件夹,则将其删除
rm -r 文件夹名 删除一个文件夹(包括里面的所有内容)
千万不要rm -rf /*,表示强制删除根目录下的所有文件,除非你相思了(doge)
cp -r 文件夹名1 文件夹名2 把文件夹1(包括里面的所有内容)复制到文件夹2
mv 文件夹名1 文件夹名2 如果文件夹名2不存在,则把文件夹名1重命名成文件夹名2;如果文件夹名2存在,则把文件夹1(包括里面所有内容)移动到文件夹2
diff 文件夹名1 文件夹名2 比较两个文件夹之间的差异
tar -cvf 文件包名.tar 文件夹名 把某个文件夹打包成名叫“文件包名.tar”的tar文件包
tar -xvf 文件包名.tar 解包这个tar文件包
zip -r 压缩包名.zip 文件夹名 把某个文件夹打包成名叫“压缩包名.zip”的压缩包
unzip 压缩包名.zip 解压这个压缩包
2. 文件
touch 文件名 创建一个文件
rm 文件名 删除一个文件
ls -l 文件名 查看文件详细信息
详细信息中,第一列是文件的权限信息(之后会讲),第二列表示指向该文件的硬链接数量,之后是文件所属的用户和文件所属的组,文件大小(单位字节),然后是最后修改时间,最后是文件名。
echo "内容" > 文件名 把内容写进文件(会覆盖前面的所有内容)
echo "内容" >> 文件名 把内容写进文件(不会覆盖前面的所有内容)
没有空格时可以不加双引号,但是有空格的时候建议加上。双引号表示会替换其中的特殊字符,单引号表示不替换。所以一般来说建议加上双引号。
mv 文件名1 文件名2 把文件名1重命名成文件名2
cat 文件名 查看文件中的所有内容,如果文件中内容过多不建议使用
cat > 文件名 编辑需要写入文件中的内容,按Ctrl + D退出
less 文件名 查看文件中的内容,仅加载当前显示的内容
more 文件名 查看文件中的内容,一次加载全部内容
cp 文件名1 文件名2 把文件1复制一份,叫文件名2
head 文件名 查看文件中的前10行内容
head -n 5 文件名 查看文件中前5行内容(5可以换成其它任意数字)
tail 文件名 查看文件中的后10行内容
tail -n 5 文件名 查看文件中后5行内容(5可以换成其它任意数字)
sort 文件名 按照ASCII顺序给文件中的内容排序
sort -r 文件名 反向排序
uniq 文件名 删除文件中重复的内容(必须在上下两排挨在一起才能删除)
sort 文件名 | uniq 先排序,再删除文件中重复的内容(可以不需要挨在一起)
grep 关键字 文件名 查找文件中包含关键字的内容。关键字可以使用正则表达式
tr a-z A-Z 文件名 查看时把文件中所有小写字母换成大写字母
nano 文件名 在GUI中编辑文件中的内容
diff 文件名1 文件名2 比较两个文件之间的差异。-i忽视大小写,-w忽视空格
wc 文件名1 统计字数
3. 重定向操作符
命令 < 文件名 把文件中的内容作为命令的输入
命令 > 文件名 把该命令的输出存入到该文件中(覆盖)
命令 >> 文件名 把该命令的输出存入到该文件中(不覆盖)
命令 0< 文件名 同 命令 < 文件名
命令 1> 文件名 同 命令 > 文件名
命令 2> 文件名 如果该命令报错,则把错误信息存入该文件中
命令1 | 命令2 把命令1的输出作为命令2的输入(这里用了匿名管道)
mkfifo 管道名 创建一个命名管道
命令 > 管道名 & 在后台把命令的输出存入管道
二. 用户权限管理
ls -l 文件名 可以查看一个文件的信息,包括权限信息。
如-rwxr-xr-x中第一个-代表文件类型(-表示普通文件),后面三个三个一组,前三个字母表示当前用户(user)的权限,中间三个是组(group)的权限,后三个是其他人(others)的权限。r代表读权限,w代表写权限,x代表执行权限,-表示没有该权限。
passwd 更改当前用户的密码
passwd 用户名 更改某个用户的密码,只有根用户有权限这么做
gpg -c 文件名 设置一段密码,把文件中的内容加密,保存为文件名.gpg
gpg -d 文件名1.gpg > 文件名2 把文件1.gpg中的内容解密到文件2
mcrypt 文件名 设置一段密码,把文件中的内容加密,保存为文件名.nc
mcrypt 文件名1.nc > 文件名2 把文件1.nc中的内容解密到文件2
chmod 三个数字 文件名 更改一个文件的权限
比如rwxr-xr--,有权限则为1,没权限则为0。二进制中前三个字母表示为111,中间三个表示为101,后三个表示为100。所以换成十进制以后,三个数字为754。
chmod 表述 文件名 更改一个文件的权限
用u, g, o, a分别代表用户(user),组(group),其他人(others),所有人(all)的权限。用+, -, =代表添加权限,移除权限和编辑权限。比如g=rwx表示让组拥有所有权限。o-w表示移除其他用户的写权限,a+x表示给所有人添加执行权限。
有一个特殊的表述u+s,可以不管运行时当前用户是谁,都以文件所有者的权限运行。
chmod +t 文件名 只允许文件拥有者或根用户重命名或删除文件
whoami 查看当前用户
其实你每次回车之后,当前用户都会显示在一行的最前面。
groups 查看当前用户所在组
chown 用户名 文件名 更改某个文件的拥有者
chown -R 用户名 文件夹名 更改某个文件夹(包括里面所有文件)的拥有者
chgrp 组名 文件名 更改某个文件所属的组
chgrp -R 组名 文件夹名 更改某个文件夹(包括里面所有文件)所属的组
su 切换到根用户,需要输入根用户的密码
su - 用户名 切换到目标用户,需要输入目标用户的密码
sudo 命令 以根用户的身份执行某项命令,需要输入当前用户的密码
三. Bash脚本
Bash脚本属于文件,所以之前对文件的操作对Bash脚本亦有效。比如:
echo "内容" >> 脚本名.sh 把内容写进Bash脚本(不会覆盖前面的所有内容)
cat 脚本名.sh 查看Bash脚本中的所有内容,如果内容过多不建议使用
1. 运行Bash脚本的方式
方法1:
bash 脚本名.sh
运行前先用ls -l 脚本名.sh查看是否有可执行权限,如果没有,需要用chmod +x 脚本名.sh确保该脚本可执行再运行。
脚本必须置于当前工作目录下,否则应使用绝对路径,如/home/user/myscript.sh。
方法2:
./脚本名.sh
注意事项同上。
此外,还要在脚本第一行使用#!Bash解释器的绝对路径。(#!也被称为Shebang)。用which bash查看Bash解释器的绝对路径,比如说是/bin/bash。那脚本的第一行就是#!/bin/bash。然后再用./脚本名.sh运行。
2. 变量
变量名=值 把值赋给变量
注意,=两边不可以加空格!
和Python有点像,不用声明变量类型,直接赋值就好了。不过使用变量时,需要在变量名前面加上$,也就是$变量名。比如echo $变量名,查看变量的值。
这种变量属于局部变量,只能在一个进程内生效。还有一种是环境变量,如下:
export 变量名=值 创建一个环境变量,环境变量可以在子进程中生效
注意,=两边不可以加空格!
变量名=$((表达式)) 把表达式的计算结果(整数)赋给变量。
表达式可以是1+1,也可以是变量名+1等。不过计算结果不能是小数。如果计算结果是小数,要变成:
变量名=$((表达式)) | bc -l 把表达式的计算结果(小数)赋给变量
set 查看所有变量。可以用set | grep 关键词筛选你要看的变量
env 只查看环境变量。可以用set | grep 关键词筛选你要看的变量
export PATH=$PATH:路径 向$PATH中添加路径作为环境变量
这样如果下一次在该路径下运行Bash脚本,只需要输入脚本名.sh就可以了。
3. 获取用户输入
read 变量名 获取用户输入,存到变量中
read -p "请输入一句话:" 变量名 -p用来在用户输入时给出一条提示语
read -sp "请输入密码:" 变量名 -s可以不显示用户输入了什么,比如输入密码的时候
read 变量名1 变量名2 ... 变量n 用户输入时用空格隔开,分别存入变量1,变量2 ...变量n
如果用户输入的比设置的变量多,多余的全都存到最后一个变量。
如果用户输入的比设置的变量少,则没有输入的变量将会被设置为空。
4. 读取文件
变量名=$(命令) 用来把命令的结果存入到变量中
如filecontents=$(cat inputfile),可以用来把inputfile文件中的内容存入到filecontents变量中。查看时echo $filecontents就行了。
4.1 从文件中读取
read 变量名 < 文件名 读取文件中的第一行,存入变量中。
想要逐行读取,需要使用while循环。以下是一个Bash脚本示例。
#!/bin/bash #每一个脚本都最好以Shebang开头。
#从用户输入获取需要读取的文件的文件名,并存到filename变量中
read -p "Enter a file to read: " filename
while read line # line是一个变量,用来存储每一行的信息
do
echo "$line" # 每读一行,就输出在屏幕上
done < $filename # 从变量存储的文件中读取
4.2 从STDIN中读取
每个命令都有三个文件STDIN,STDOUT和STDERR。管道的作用是把前一个命令的STDOUT连接到后一个命令的STDIN。
以下是一个从STDIN中读取内容的脚本。
#!/bin/bash
while read line
do
echo "$line"
done < /dev/stdin # 这个地址是存储STDIN的地方
读取时,可以用管道把一个命令的输出作为这个脚本的输入,如cat 文件名 | ./该脚本.sh,也可以用重定向符,将指定文件的内容作为标准输入传递给脚本,如./该脚本.sh < 文件名。
5. 命令行参数
$0 程序名称
$1, …, $9 第1个参数...第9个参数
$* 所有参数
$@ 与$*相同,但每个参数单独用引号括起来
$# 参数总数
$$ 当前进程的进程ID(PID)
$? 最近一个命令的退出状态
$! 最近一个后台进程的PID
6. 提供选项
#!/bin/bash
echo "Which action would you like to perform?"
select action in 选项1 选项2 quit
do
case $action in
选项1 ) 选项1对应的命令;;
选项2 ) 选项2对应的命令;;
quit ) break;;
* ) echo "Unknown action";;
esac
done
7. 控制流
执行完一个命令之后,会有一个退出状态表示该命令是否执行成功,可以使用echo $?查看。如果值为0,则表示执行成功,如果为1-255中任意一个数,则表示执行失败。
7.1 If分支结构
if [ 表述1 ]; then
命令1
elif [ 表述2 ]; then
命令2
else
命令3
fi #用来结束
[ 表述 ]可以换为test 表述或者一个命令。如果表述正确(或命令运行成功),则结束状态为0,若表述错误(或命令运行失败),则为1。注意[ 表述 ]中,前后两个空格不能少。常用的表述如下:
字符串1 = 字符串2 两个字符串是否相等。
=前后需要有空格!
字符串1 != 字符串2 两个字符串是否不相等。
!=前后需要有空格!
-d 文件名 该文件是否为目录
-e 文件名 该文件是否存在
-f 文件名 该文件是否存在且为普通文件
-r 文件名 当前用户能否读该文件
-w文件名 当前用户能否写该文件
-x文件名 当前用户能否执行该文件
-z 字符串 该字符串是否为空
num1 -lt num2 num1是否小于num2
num1 -gt num2 num1是否大于num2
num1 -eq num2 num1是否等于num2
7.2 Case分支结构
case $变量 in
情况1 )
命令1
;;
情况2 )
命令2
;;
情况3 )
命令3
;;
* )
命令4
;;
esac
* )表示其它任意情况。
7.3 While循环结构
while [ 情况1 ]; do
命令
done
7.4 Until结构
until [ 条件 ]; do
命令
done
7.5 For循环结构
for 变量名 in 一系列用空格隔开的东西; do
commands
done
循环结构都可以用break和continue。
一系列用空格隔开的东西也可以是$(ls xxx)等能生成一系列用空格隔开的东西的命令。
8. 函数
8.1 定义函数
function 函数名 {
函数内容
}
或
函数名 () {
函数内容
}
函数名后面的括号里不能有任何参数!函数定义必须在函数调用之前。
8.2 函数参数
参数在函数内容中用$1,$2等来代替,类似于前面提到的变量。
以下是定义一个函数的例子:
print () {
echo $1
}
还有一种办法是在函数内部用局部变量。
local 变量名=值
在函数内调用该变量时就$变量名就行了,但是在函数外部局部变量会失效。
8.3 函数返回值
Bash脚本中没有返回值。所以你要输出什么就echo出来。
8.4 调用函数
函数名 参数1 参数2 ...
比如8.2提到的那个print函数的调用方式就是
print "Hello world"
那么输出结果就是Hello world。
8.5 函数覆写
可以取和系统中的函数名字相同的函数,这样就会覆盖系统函数。使用系统函数时,用command 系统函数。
四. 进程管理
ps 显示当前正在运行的进程
ps -f 显示当前正在运行的进程的详细信息
UID:用户ID,拥有该进程的用户。PID:进程ID。PPID:父进程的ID。C:CPU占用率。STIME:启动时间。TTY:控制终端,该进程连接的终端设备。TIME:累记CPU使用时间。CMD:命令行,启动进程时使用的完整命令行。
pidof 进程 查看该进程的PID
echo $$ 查看此进程的ID
echo $PID 查看此进程的父进程ID
$$和$PID是环境变量
pstree -pn 显示进程的层级结构,-p用来显示PID,-n用来按照PID排序
ps -ef 显示系统上运行的所有进程
top 实时查看进程及其占用情况
命令 & 在后台执行该命令
jobs -l 列出正在后台运行的工作的详细信息
fg % 把正在后台运行的工作转移至前台
%可以替换为:% 或 %+ 当前工作;%- 之前的工作;%数字 工作序号为数字的工作;%名字 以名字开头的工作;%?名字 包含该名字的工作
命令 按Ctrl+Z 暂停该命令的进程,并转移至后台
bg % 重新在后台启动当前被暂停的工作
命令1; 命令2 按顺序执行命令1和命令2
命令1 & 命令2 把命令1在后台执行,同时在前台执行命令2
命令1 && 命令2 如果命令1成功,执行命令2
命令1 || 命令2 如果命令1失败,执行命令2
命令 按Ctrl+C 结束该命令的进程
kill % 结束在后台运行的工作
kill是向进程发送信号,kill % 默认为kill -15 %,表示正常终止进程。比较常用的信号有:-1:挂起,-2:中断(Ctrl+C),-9:强制终止,-15:正常终止,-17:暂停,-18:暂停(Ctrl+Z),-19:继续。
五. 其它
1. 在debug模式下运行脚本
方法1:把Shebang改为#!/bin/bash -x
方法2:运行时用bash -x 脚本名.sh
2. tee操作
命令 tee -a 文件名 将命令的输出存入文件中,并显示在屏幕上
3. 异常处理
举例:
if [ 会产生错误的命令 ]; then
echo "An error occurred" >> error.log
echo "An error occurred" 1>&2
exit 1
fi
注:echo "An error occurred" >> error.log用来把这条信息写进名叫error.log的日志文件。echo "An error occurred" >&2用来把这条信息输出到标准错误。其中>&2用来把标准输出重定向到标准错误。
可以用tee把两句话合在一起,变成echo "An error occurred" | tee -a error.log >&2既能写进日志文件,又能输出到标准错误。其中-a表示表示append,只添加不覆盖。
if [ 会产生错误的命令 ]; then
echo "An error occurred" | tee -a error.log >&2
exit 1
fi
4. heredoc
有时候需要在交互式界面打出好几行的内容,想要换行,但是按回车它就自动执行了。这个时候可以用heredoc。
命令 << EOF
第一行要写的内容
第二行要写的内容
EOF
也可以把多行内容写进文件,如
cat << EOF > 文件名
第一行要写的内容
第二行要写的内容
EOF
5. trap命令
trap "命令" 信号 当捕捉到某个信号时,执行某个命令。信号之前在kill那里讲过,可以通过kill -l来查看有哪些信号。例如,以下是收到退出命令后删除临时文件的用法
trap "rm -f temp.txt; exit" EXIT
6. 变量的高级用法
之前讲过$的三种用法,$(命令),$((数学运算)),$变量。其中$变量表示获取变量的值,还有一种写法是$(变量)。
比如var="Hello world",以下是几个运用举例
echo $(var)结果是Hello world
echo $(var:2)结果是llo world,即从第2个(从0开始数)往后的所有。
echo $(var:6:3)结果是wor,即从第6个(从0开始数)往后3个
${var:-Hello}表示如果var变量未被设置或为空,则使用Hello的值。如果var 已经设置了值,则使用var的值。
${var:=Hello}表示如果var变量未被设置或为空,则将Hello赋值给var,并使用Hello的值。如果var已经设置了值,则使用var的值。
${#var}结果是11,即变量的长度
${var^^}结果是HELLO WORLD,把变量变成大写
${var,,}结果是hello world,把结果变成小写
${var/o/O}结果是HellO world,把第一个小o替换成大O
${var//o/X}结果是HellO wOrld,把所有小o都替换成大O
7. 数组
数组名=(元素1 元素2 元素3...) 创建数组
${数组名} 默认为数组中的第一个元素
${数组名[序号]} 访问数组中的元素,序号从0开始。
${数组名[*]} 或 ${数组名[@]} 数组中的所有元素
${数组名[@]:1} 数组中从第1个(从0开始数)开始往后的所有元素
${数组名[@]:1:2} 数组中从第1个(从0开始数)开始往后两个
8. getopts
示例:
while getopts ":xrf:" opt; do
case ${opt} in
x ) echo "Option x" ;;
f ) echo "Option f with argument $OPTARG" ;;
r ) echo "Option r" ;;
\? ) echo "Unknown option" ;;
: ) echo "$OPTARG requires an argument" 1>&2 ;;
esac
done
f:表示-f后面需要参数。