命令帮助
终端输入下面其中一个命令,可以查看该命令的使用帮助
- 命令 --help
- man 命令
文件系统
文件系统结构
- /(根目录)
- bin(存储常用的可执行文件、命令)
- etc(一般用于存储配置文件)
- var(一般用于存储日志文件)
- lib(一般用于存储安装包、静态链接库)
- home(一般用于存储用户的家目录,一个Linux系统可以有多个用户,不同用户对应不同的家目录)
- proc(一般用于存储Linux系统的一些配置文件,可以看到Linux系统的信息)
路径
-
绝对路径:开头是 /
-
相对路径:开头不是 /
-
.:当前目录
-
…:上级目录
-
~/:家目录
acs@80826ae841a9:~/temp$ pwd
/home/acs/temp
acs@80826ae841a9:~/temp$ cd .. # 回到上级目录
acs@80826ae841a9:~$ pwd
/home/acs
acs@80826ae841a9:~$ cd . # 回到当前目录
acs@80826ae841a9:~$ pwd
/home/acs
acs@80826ae841a9:~$
acs@80826ae841a9:/$ pwd
/
acs@80826ae841a9:/$ cd ~/ # 回到家目录
acs@80826ae841a9:~$ pwd
/home/acs
acs@80826ae841a9:~$
常用文件管理命令
-
键盘按下CTRL + c:结束正在运行的程序,取消正在输入的本行命令,并且换行
-
键盘按下CTRL + u:清空正在输入的本行且在光标之前的命令
-
键盘按下TAB:可以补全命令或文件名,如果补全不了可以快速按两下TAB键,则可以显示备选选项
-
键盘按下方向键 ↑ :可以自动输入上一次执行的命令
-
history:显示使用过的历史指令
-
ls:列出当前目录下所有文件,蓝色的是文件夹,白色的是普通文件,绿色的是可执行文件(在ACWing的终端中)
- ls -l:展示详细信息
- ls -hl:以人性化展示详细信息
- ls -a:能够展示所有文件,包括隐藏文件(所有隐藏文件的文件名以.开头)
-
pwd:显示当前路径
-
cd:切换目录
-
cd -:返回上一次所在的目录
-
cp:复制粘贴文件、复制粘贴目录
acs@80826ae841a9:~$ pwd /home/acs acs@80826ae841a9:~$ ls a b acs@80826ae841a9:~$ cp a/tmp.txt b # 把a目录下的tmp.txt文件复制粘贴到b目录下 acs@80826ae841a9:~$
acs@80826ae841a9:~$ pwd /home/acs acs@80826ae841a9:~$ ls a b acs@80826ae841a9:~$ cp a/tmp.txt b/tmp2.txt # 把a目录下的tmp.txt文件复制粘贴到b目录下并且重命名为tmp2.txt acs@80826ae841a9:~$
acs@80826ae841a9:~$ pwd /home/acs acs@80826ae841a9:~$ ls a b acs@80826ae841a9:~$ cp a b -r # 把整个a目录复制粘贴到b目录下 acs@80826ae841a9:~$ ls a b acs@80826ae841a9:~$ cd b acs@80826ae841a9:~/b$ ls a tmp2.txt acs@80826ae841a9:~/b$
acs@80826ae841a9:~$ pwd /home/acs acs@80826ae841a9:~$ ls a b 'te p' 'y c' acs@80826ae841a9:~$ cp a c -r # 把整个a目录复制粘贴到当前目录下,并且重命名为c acs@80826ae841a9:~$ ls a b c 'te p' 'y c' acs@80826ae841a9:~$
-
touch:创建文件
acs@80826ae841a9:~$ pwd /home/acs acs@80826ae841a9:~$ ls a b 'y c' acs@80826ae841a9:~$ touch te\ p # 创建文件,文件名有空格的使用转义字符\ acs@80826ae841a9:~$ ls a b 'te p' 'y c' acs@80826ae841a9:~$
-
mkdir:创建目录
acs@80826ae841a9:~$ pwd /home/acs acs@80826ae841a9:~$ ls a b acs@80826ae841a9:~$ mkdir y\ c # 创建目录,目录名有空格的使用转义字符\ acs@80826ae841a9:~$ ls a b 'y c' acs@80826ae841a9:~$
acs@80826ae841a9:~$ pwd /home/acs acs@80826ae841a9:~$ ls acs@80826ae841a9:~$ mkdir a/b/c -p # 在当前目录下创建a目录,在a目录下创建b目录,在b目录下创建c目录 acs@80826ae841a9:~$ ls a acs@80826ae841a9:~$ ls a/ b acs@80826ae841a9:~$ ls a/b/ c acs@80826ae841a9:~$
-
rm:删除文件、删除目录
acs@80826ae841a9:~/a/b$ pwd /home/acs/a/b acs@80826ae841a9:~/a/b$ ls c tmp.txt tmp2.txt acs@80826ae841a9:~/a/b$ rm tmp.txt tmp2.txt # 删除tmp.txt和tmp2.txt文件 acs@80826ae841a9:~/a/b$ ls c acs@80826ae841a9:~/a/b$ rm c -r # 删除一整个c目录 acs@80826ae841a9:~/a/b$ ls
acs@80826ae841a9:~$ pwd /home/acs acs@80826ae841a9:~$ ls a acs@80826ae841a9:~$ find a a a/t1.txt a/t2.txt a/b acs@80826ae841a9:~$ rm a/* -r # 删除a目录下的所有东西 acs@80826ae841a9:~$ cd a acs@80826ae841a9:~/a$ ls acs@80826ae841a9:~/a$
-
mv:剪切粘贴文件、剪切粘贴目录。用法和cp一模一样,只不过mv是剪切粘贴,cp是复制粘贴
acs@80826ae841a9:~/a$ pwd /home/acs/a acs@80826ae841a9:~/a$ ls t1.txt acs@80826ae841a9:~/a$ mv t1.txt t2.txt # 可以实现重命名 acs@80826ae841a9:~/a$ ls t2.txt acs@80826ae841a9:~/a$
-
cat:展示文件中的内容
-
键盘按下CTRL + INSERT:复制文本
-
键盘按下SHIFT + INSERT:粘贴文本
在终端上复制超过窗口大小展示的内容的方法
- 先用cat命令把文件中的内容展示到终端上
- 然后用鼠标左键选中内容的开头
- 然后用鼠标滚轮往下翻,找到内容的结尾
- 然后键盘按住SHIFT键,接着用鼠标左键选中内容的结尾
- 然后键盘按下CTRL + INSERT进行文本的复制即可!!!
知识点补充
-
ag命令,可以进行全文搜索
acs@80826ae841a9:~/homework/lesson_3/homework_4$ pwd /home/acs/homework/lesson_3/homework_4 acs@80826ae841a9:~/homework/lesson_3/homework_4$ ls main.sh acs@80826ae841a9:~/homework/lesson_3/homework_4$ ag sum main.sh # 全文搜索sum出现的位置 5:sum=0 9: sum=$(expr ${sum} + $(expr ${i} \* ${i})) 12:echo ${sum} > ${2} acs@80826ae841a9:~/homework/lesson_3/homework_4$
-
tree命令,可以展示当前路径下的目录文件结构
acs@80826ae841a9:~/homework/lesson_3$ pwd /home/acs/homework/lesson_3 acs@80826ae841a9:~/homework/lesson_3$ ls homework_0 homework_1 homework_2 homework_3 homework_4 acs@80826ae841a9:~/homework/lesson_3$ tree . # 展示当前路径下的目录文件结构 . |-- homework_0 | `-- helper.sh |-- homework_1 | `-- check_file.sh |-- homework_2 | `-- main.sh |-- homework_3 | `-- main.sh `-- homework_4 `-- main.sh 5 directories, 5 files acs@80826ae841a9:~/homework/lesson_3$
tmux
tmux的两个重要作用
- 可以分屏操作,每个屏幕都是一个Terminal(终端),操作同一个服务器
- 允许断开Terminal(终端)连接后,继续运行进程(可以保证在突然断电的情况下,进程继续运行或正在写的文档内容不消失)
tmux的结构(一个tmux可以包含多个session,一个session可以包含多个window,一个window可以包含多个pane):
- session
- window
- pane
- window
常用操作:
-
tmux:新建一个session,其中包含一个window,window中包含一个pane,pane里打开了一个shell对话框
-
键盘按下CTRL + a后,手指松开,然后按%:将当前pane左右平分成两个pane
-
键盘按下CTRL + a后,手指松开,然后按":将当前pane上下平分成两个pane
-
键盘按下CTRL + d:关闭当前pane;如果当前window的所有pane均已关闭,则自动关闭window;如果当前session的所有window均已关闭,则自动关闭session
-
鼠标点击可以直接选pane
-
键盘按下CTRL + a后手指松开,然后按方向键:选择相邻的pane
-
鼠标拖动pane之间的分割线,可以调整分割线的位置
-
键盘按住CTRL + a的同时按方向键,可以调整pane之间分割线的位置
-
键盘按下CTRL + a后手指松开,然后按z:将当前pane全屏或者取消全屏
-
键盘按下CTRL + a后手指松开,然后按d:挂起当前session(即退出tmux,但是不关闭窗口)
-
tmux a:打开之前挂起的session
-
键盘按下CTRL + a后手指松开,然后按s,然后按方向键
- 上:选择上一项 session/window/pane
- 下:选择下一项 session/window/pane
- 右:展开当前项 session/window
- 左:闭合当前项 session/window
-
键盘按下CTRL + a后手指松开,然后按c:在当前session中创建一个新的window**(不常用)**
-
键盘按下CTRL + a后手指松开,然后按w,然后按方向键。操作跟上面那个类似,区别是这里会默认打开window这一级
-
鼠标滚轮:翻阅当前pane内的内容
-
键盘按下CTRL + a后手指松开,然后按PageUp或PageDown:翻阅当前pane内的内容
-
在tmux中要选中文本时,需要按住shift键,然后可以进行复制粘贴
-
在tmux中复制粘贴文本的通用方式:
- 键盘按下CTRL + a后松开手指,然后按[
- 用鼠标选中文本,被选中的文本会被自动复制到tmux的剪贴板
- 键盘按下CTRL + a后松开手指,然后按],会将tmux的剪贴板中的内容粘贴到光标处
vim
vim:命令行模式下的文本编辑器
vim可以根据文件扩展名自动判别编程语言,支持代码缩进、代码高亮等功能
使用vim
- vim (filename):
- 如果已有该文件,则打开它
- 如果没有该文件,则打开个一个新的文件,并命名为filename
vim的三种模式
- 一般命令模式(默认)
- 键盘按下不同的健,即可进行不同操作,可以复制、粘贴、删除文本等等
- 在一般命令模式里键盘按下i或a或o这三个字符中的任意一个,则会进入编辑模式
- 在一般命令模式里键盘按下:或/或?这三个字符中的任意一个,则会进入命令行模式
- 编辑模式
- 键盘按下ESC,会退出编辑模式,返回到一般命令模式
- 命令行模式
- 可以查找、替换、保存、退出、配置编辑器等等
vim的常用操作:
- 键盘按下h 或 左箭头键:光标向左移动一个字符,不允许换行
- 键盘按下j 或 向下箭头:光标向下移动一个字符
- 键盘按下k 或 向上箭头:光标向上移动一个字符
- 键盘按下l 或 向右箭头:光标向右移动一个字符,不允许换行
- 键盘按下n(n为数字),然后再按下空格键:光标会向右移动n个字符,允许换行
- 键盘按下0 或 Home:光标移动到本行开头
- 键盘按下$ 或 End:光标移动到本行末尾
- 键盘按下G:光标移动到最后一行
- 键盘按下:n 或 nG(n为数字):光标移动到第n行
- 键盘按下gg:光标移动到第一行,相当于键盘按下1G
- 键盘按下n(n为数字),然后再按下回车:光标向下移动n行
- 键盘按下/word:从当前光标位置开始,往下寻找第一个值为word的字符串(用于查找字符串)
- 键盘按下?word:从当前光标位置开始,往上寻找第一个值为word的字符串(用于查找字符串)
- 键盘按下n:重复前一个查找操作
- 键盘按下N:反向重复前一个查找操作
- 键盘按下:n1,n2s/word1/word2/g:n1与n2为数字,在第n1行与n2行之间(包括n1和n2)寻找word1这个字符串,并将该字符串替换为word2(用于替换字符串,注意不要漏掉s,和末位的g)
- 键盘按下:1,$s/word1/word2/g:将全文的word1替换为word2(用于替换字符串,注意不要漏掉s,和末位的g)
- 键盘按下:1,$s/word1/word2/gc:将全文的word1替换为word2,且在替换前要求用户确认是否替换(用于替换字符串,注意不要漏掉s,和末位的gc)
- 键盘按下:noh:关闭查找关键词产生的高亮
- 键盘按下v后松开,然后按下方向键:可以选中文本,再按一次v可以退出选中状态
- 键盘按下d:剪切选中的文本,粘贴时是在光标的下一个位置粘贴
- 键盘按下dd:剪切当前行,粘贴时是在光标的下一行位置粘贴
- 键盘按下y:复制选中的文本,粘贴时是在光标的下一个位置粘贴
- 键盘按下yy:复制当前行,粘贴时是在光标的下一行位置粘贴
- 键盘按下p:将复制或剪切的数据在光标的下一行或下一个位置粘贴
- 键盘按下u:撤销
- 键盘按下CTRL + r:取消撤销
- 键盘按下SHIFT + >:将选中的文本整体向右缩进一次
- 键盘按下SHIFT + <:将选中的文本整体向左缩进一次
- 键盘按下:w:保存
- 键盘按下:w!:强制保存
- 键盘按下:q:退出
- 键盘按下:q!:强制退出
- 键盘按下:wq:保存并退出
- 键盘按下:wq!:强制保存并退出
- 键盘按下:set nu:显示行号
- 键盘按下:set nonu:隐藏行号
- 键盘按下:set paste:设置成粘贴模式,取消代码自动缩进
- 键盘按下:set nopaste:设置成非粘贴模式,开启代码自动缩进
- 键盘按下CTRL + q:当vim卡死时,可以取消当前正在执行的命令
vim的常用组合键:
- 键盘按下ggdG:删除全文
- 键盘按下gg=G:全文代码格式化(当全文代码很长时,此方式会占用很大带宽)
vim的异常处理:
- 每次用vim编辑文件时,会自动创建一个.filename.swp的临时文件,如果打开某个文件时,该文件的swp文件已存在,则会报错
- 此时解决办法有两种:
- 找到正在打开该文件的程序,并退出
- 直接删掉该swp文件即可
- 此时解决办法有两种:
shell语法
概论
- shell是我们通过命令行与操作系统沟通的语言
- shell脚本可以直接在命令行中执行,也可以将一套逻辑组织成一个文件,方便复用
- AC Terminal中的命令行可以看成是一个“shell脚本在逐行执行”
- Linux中常见的shell脚本有很多种,常见的有
- Bourne Shell(/usr/bin/sh或/bin/sh)
- Bourne Again Shell(/bin/bash)(这个是最常用的)
- C Shell(/usr/bin/csh)
- K Shell(/usr/bin/ksh)
- zsh
- .sh文件开头需要写上 #! /bin/bash 这一行(注意不要加分号;),作用是指明bash为脚本的解释器
示例:新建一个test.sh文件,内容如下
#! /bin/bash
# echo会自动换行
echo "Hello World!"
echo Hello World!!! # 也可以写成这种,不加双引号的
第一种运行方式:直接用解释器执行,该文件不需要有可执行权限也可以
acs@80826ae841a9:~/temp$ pwd
/home/acs/temp
acs@80826ae841a9:~/temp$ ls
temp.cpp test.sh
acs@80826ae841a9:~/temp$ bash test.sh # 直接用解释器执行
Hello World!
Hello World!!!
acs@80826ae841a9:~/temp$
第二种运行方式:把test.sh作为可执行文件,该文件必须要有可执行权限
acs@80826ae841a9:~/temp$ pwd
/home/acs/temp
acs@80826ae841a9:~/temp$ ls
temp.cpp test.sh
acs@80826ae841a9:~/temp$ ls -l test.sh
-rw-rw-r-- 1 acs acs 34 Aug 5 23:33 test.sh
acs@80826ae841a9:~/temp$ chmod +x test.sh # 添加可执行权限
acs@80826ae841a9:~/temp$ ls -l test.sh
-rwxrwxr-x 1 acs acs 34 Aug 5 23:33 test.sh
acs@80826ae841a9:~/temp$ ./test.sh # 在当前路径下执行
Hello World!
acs@80826ae841a9:~/temp$ test.sh # 这么写是错误的,必须要加上./
-bash: test.sh: command not found
acs@80826ae841a9:~/temp$ /home/acs/temp/test.sh # 在绝对路径下执行。也可以在相对路径下执行
Hello World!
acs@80826ae841a9:~/temp$
注释
单行注释
#! /bin/bash
# 这是一行注释
多行注释:其中EOF可以换成其它任意字符串
#! /bin/bash
:<<EOF
注释1
注释2
注释3
注释4
...
EOF
:<<abc
注释1
注释2
注释3
注释4
...
abc
:<<!
注释1
注释2
注释3
注释4
...
!
变量
- 定义变量和使用变量
#! /bin/bash
# 定义变量
name1="yxc" # 注意等于号左右两边不能有空格
name2='yxc'
name3=yxc
# 使用变量
echo $name3
echo ${name3} # 一般推荐使用这种方式,存在明确边界
echo ${name3}acwing
echo "${name3}acwing"
- 使用 readonly 或者 declare -r 可以将变量变为只读变量
#! /bin/bash
name1=yxc
readonly name1 # 将变量定义为只读变量
name2=acwing
declare -r name2 # 将变量定义为只读变量
- 删除变量
#! /bin/bash
name=yxc
unset name # 删除变量
echo ${name} # 输出为空值
- 变量类型
- 自定义变量(局部变量),即子进程不能访问的变量
- 环境变量(全局变量),即子进程可以访问的变量
自定义变量改成环境变量(当前在tmux中操作,一个pane里面的bash即可视为一个进程):
acs@80826ae841a9:~/temp$ name=yxc # 定义变量
acs@80826ae841a9:~/temp$ export name # 第一种方法,将自定义变量改成环境变量
acs@80826ae841a9:~/temp$ declare -x name # 第二种方法,将自定义变量改成环境变量
acs@80826ae841a9:~/temp$
acs@80826ae841a9:~/temp$ bash # 可以进入到一个新的bash中,即视为开了一个子进程,原来的进程则会进入睡眠
acs@80826ae841a9:~/temp$ echo $name # 子进程中可以访问环境变量
yxc
acs@80826ae841a9:~/temp$ exit # 退出子进程
exit
acs@80826ae841a9:~/temp$
环境变量改成自定义变量(当前在tmux中操作,一个pane里面的bash即可视为一个进程):
acs@80826ae841a9:~/temp$ name=yxc # 定义变量
acs@80826ae841a9:~/temp$ export name # 将自定义变量改成环境变量
acs@80826ae841a9:~/temp$ declare +x name # 将环境变量改成自定义变量
acs@80826ae841a9:~/temp$
acs@80826ae841a9:~/temp$ bash # 可以进入到一个新的bash中,即视为开了一个子进程,原来的进程则会进入睡眠
acs@80826ae841a9:~/temp$ echo $name # 子进程中不能访问自定义变量
acs@80826ae841a9:~/temp$ exit # 退出子进程
exit
acs@80826ae841a9:~/temp$
acs@80826ae841a9:~/temp$ echo name
name
acs@80826ae841a9:~/temp$
- 字符串,可以用单引号,也可以用双引号,也可以不用引号
- 单引号与双引号**(不用引号和用双引号一样)**的区别:
- 单引号中的内容会原样输出,不会执行、不会取变量、不会转义
- 双引号中的内容可以执行、可以取变量、可以转义
- 获取字符串长度
- 获取字符串的子串
- 单引号与双引号**(不用引号和用双引号一样)**的区别:
#! /bin/bash
name=yxc
echo 'hello, $name \"hh\"' # 单引号字符串,输出:hello, $name \"hh\"
echo "hello, $name \"hh\"" # 双引号字符串,输出:hello, yxc "hh"
echo hello, $name \"hh\" # 不用引号字符串,输出:hello, yxc "hh"
echo ${#name} # 能够输出字符串长度,输出:3
temp="hello,yxc"
echo ${temp:0:5} # 输出从下标为0开始,长度为5的子串,输出:hello
默认变量
-
文件参数变量
-
在执行shell脚本时,可以向脚本传递参数
-
脚本内容如下
#! /bin/bash echo "文件名:"${0} echo "第一个参数:"${1} echo "第二个参数:"${2} echo "第三个参数:"${3} echo "第四个参数:"${4} echo "传入的参数个数:"${#} echo "输出由所有参数构成的用空格隔开的字符串:"${*} echo "输出每个参数分别用双引号括起来的字符串:"${@} echo "当前脚本的进程ID:"${$} echo "输出上一条命令的退出状态(exit code),0表示正常退出,其他值表示错误:"${?} # echo "返回command这条命令的stdout(可嵌套):"$(command) echo "返回ls这条命令的stdout(可嵌套):"$(ls) # echo "返回command这条命令的stdout(不可嵌套):"`command` echo "返回pwd这条命令的stdout(不可嵌套):"`pwd`
-
执行脚本
acs@80826ae841a9:~/temp$ pwd /home/acs/temp acs@80826ae841a9:~/temp$ ls temp.cpp test.sh acs@80826ae841a9:~/temp$ ./test.sh yxc 12 cgw 18 文件名:./test.sh 第一个参数:yxc 第二个参数:12 第三个参数:cgw 第四个参数:18 传入的参数个数:4 输出由所有参数构成的用空格隔开的字符串:yxc 12 cgw 18 输出每个参数分别用双引号括起来的字符串:yxc 12 cgw 18 当前脚本的进程ID:2357 输出上一条命令的退出状态(exit code),0表示正常退出,其他值表示错误:0 返回ls这条命令的stdout(可嵌套):temp.cpp test.sh 返回pwd这条命令的stdout(不可嵌套):/home/acs/temp acs@80826ae841a9:~/temp$
-
-
数组
数组中可以存放多个不同类型的值,只支持一维数组,初始化时不需要指明数组大小,数组下标从0开始,数组下标灵活
-
定义
#! /bin/bash # 第一种定义方式,数组用小括号表示,元素之间用空格隔开 array1=(1 abc "def" 'yxc') # 第二种定义方式,直接定义数组中某个元素的值 array2[0]=1 array2[1]=abc array2[2]="def" array2[3]='yxc' # 第三种定义方式,可以直接定义空数组 array3=
-
读取数组中某个元素的值
-
脚本内容如下
#! /bin/bash # 第一种定义方式,数组用小括号表示,元素之间用空格隔开 array1=(1 abc "def" 'yxc') # 第二种定义方式,直接定义数组中某个元素的值 array2[0]=1 array2[1]=abc array2[2]="def" array2[1000]='yxc' # 数组下标灵活,array2数组的长度是4,不是1000 # 读取数组中某个元素的值 echo ${array1[0]} echo ${array1[1]} echo ${array1[2]} echo ${array1[3]} echo "---------------" echo ${array2[0]} echo ${array2[1]} echo ${array2[2]} echo ${array2[1000]}
-
执行脚本
acs@80826ae841a9:~/temp$ ./test.sh 1 abc def yxc --------------- 1 abc def yxc acs@80826ae841a9:~/temp$
-
-
读取整个数组
-
脚本内容如下
#! /bin/bash array=(1 abc "def" 'yxc') # 读取整个数组 echo ${array[*]} # 第一种写法 echo "---------------" echo ${array[@]} # 第二种写法
-
执行脚本
acs@80826ae841a9:~/temp$ ./test.sh 1 abc def yxc --------------- 1 abc def yxc acs@80826ae841a9:~/temp$
-
-
读取数组长度
-
脚本内容如下
#! /bin/bash array=(1 abc "def" 'yxc') # 读取数组长度 echo ${#array[*]} # 第一种写法 echo "---------------" echo ${#array[@]} # 第二种写法
-
执行脚本
acs@80826ae841a9:~/temp$ ./test.sh 4 --------------- 4 acs@80826ae841a9:~/temp$
-
expr命令
- expr命令:用于求表达式的值
关于表达式的说明:
- 用空格隔开每一项
- 用反斜杠放在shell特定的字符前面(发现表达式运行错误时,可以试试转义)
- 对包含空格和其他特殊字符的字符串要用引号括起来
- **expr命令执行后本身会在stdout中输出结果:**如果为逻辑关系表达式,则结果为真时输出1,结果为假时输出0
- expr命令的exit code(退出状态):0表示真,非0表示假
三种表达式的优先级:逻辑关系表达式 < 算术表达式 < 字符串表达式
字符串表达式
-
求字符串长度
-
脚本内容如下
#! /bin/bash str="Hello World!" echo $(expr length "${str}") # 如果字符串存在空格,则需要加上双引号
-
执行脚本
acs@80826ae841a9:~/temp$ ./test.sh 12 acs@80826ae841a9:~/temp$
-
-
返回给定字符集中的任意单个字符在字符串中最早出现的位置(位置从1开始数),如果没有结果则返回0
-
脚本内容如下
#! /bin/bash str="Hello World!" echo $(expr index "${str}" aWd)
-
执行脚本
acs@80826ae841a9:~/temp$ ./test.sh 7 acs@80826ae841a9:~/temp$
-
-
截取字符串
-
脚本内容如下
#! /bin/bash str="Hello World!" echo $(expr substr "${str}" 2 3) # 输出从第2个字母开始长度为3的字符串
-
执行脚本
acs@80826ae841a9:~/temp$ ./test.sh ell acs@80826ae841a9:~/temp$
-
整数表达式(算术表达式)
- 加,减运算:两端参数会转换为整数,如果转换失败则报错
- 乘,除,取模运算:两端参数会转换为整数,如果转换失败则报错
- 括号可以改变优先级,但需要用反斜杠转义
脚本内容如下
#! /bin/bash
a=3
b=4
# 加减
echo $(expr ${a} + ${b}) # 这种写法比较麻烦
echo `expr $a - $b`
echo "--------------------------"
# 乘除取模
echo `expr $a \* $b` # *需要转义
echo `expr $a / $b`
echo `expr $a % $b`
echo "--------------------------"
# 添加括号
echo `expr \( $a + 1 \) \* \( $b + 1 \)`
执行脚本
acs@80826ae841a9:~/temp$ ./test.sh
7
-1
--------------------------
12
0
3
--------------------------
20
acs@80826ae841a9:~/temp$
逻辑关系表达式
-
|
- 如果第一个参数非空且非0, 则返回第一个参数的值,否则如果第二个参数的值非空且非0,就返回第二个参数的值,否则返回0
- 遵循短路原则
-
&
- 如果两个参数都非空且非0,则返回第一个参数,否则返回0
- 遵循短路原则
-
<(小于)<=(小于等于)=(等于)==(等于)!=(不等于)>(大于)>=(大于等于)
- 比较两端的参数,如果为true,则返回1,否则返回0
- ==和=是同义词
- expr首先尝试将两端参数转换为整数,如果转换失败,则按字符集排序规则做字符比较
- 括号可以改变优先级,但需要用反斜杠转义
脚本内容如下
#! /bin/bash
a=3
b=4
c=0
d=5
echo `expr $c \& $d`
echo `expr $a \& $b`
echo `expr $c \| $d`
echo `expr $a \| $b`
echo "---------------------"
echo `expr $a \> $b` # >需要转义
echo $? # 上一条命令的exit code为0
echo "---------------------"
expr $a \> $b # >需要转义,expr命令执行后本身会在stdout中输出结果
echo $? # 上一条命令的exit code为1
echo "---------------------"
echo `expr $a '<' $b` # 也可以用引号引起来,不一定要用反斜杠转义
echo `expr $a '>=' $b`
echo `expr $a \<\= $b`
执行脚本
acs@80826ae841a9:~/temp$ ./test.sh
0
3
5
3
---------------------
0
0
---------------------
0
1
---------------------
1
0
1
acs@80826ae841a9:~/temp$
read命令
- read命令:用于从标准输入中读取单行数据,当读到文件结束符时,exit code为1,否则为0
- 文件结束符为:键盘按下CTRL + d
- 参数说明:
- -p:后面可以接提示信息
- -t:后面跟秒数,定义输入字符的等待时间,超过等待时间后会自动忽略此命令
脚本内容如下
#! /bin/bash
# read 变量名
read name1 # 变量名不需要加$
echo Hello,$name1!
echo "----------------------------------"
read -p "What'a is your name?" name2
echo Hello,$name2!
echo "----------------------------------"
read -p "What'a is your name?" -t 5 name3 # 读入name3的值,等待时间5秒
echo Hello,$name3!
执行脚本
acs@80826ae841a9:~/temp$ ./test.sh
yxc
Hello,yxc!
----------------------------------
What'a is your name?cgw
Hello,cgw!
----------------------------------
What'a is your name?Hello,!
acs@80826ae841a9:~/temp$
知识点补充
acs@80826ae841a9:~/temp$ read name
yxc
acs@80826ae841a9:~/temp$ echo ${?}
0
acs@80826ae841a9:~/temp$ read name # 直接读入文件结束符,键盘按下CTRL + d
acs@80826ae841a9:~/temp$ echo ${?} # 读到文件结束符时,上一条命令的退出状态(exit code)为1
1
acs@80826ae841a9:~/temp$
echo命令
- echo命令:用于输出字符串
- 显示普通字符串
- 显示转义字符
- 显示变量
- 显示换行
- 显示不换行
- 显示结果定向至文件
- 原样输出字符串,不进行转义或取变量(用单引号)
- 显示命令的执行结果
脚本内容如下
#! /bin/bash
# 显示普通字符串
echo "Hello AC Terminal"
echo Hello AC Terminal
echo "-----------------------------------"
# 显示转义字符
echo "\"Hello AC Terminal\"" # 注意只能使用双引号,如果使用单引号,则不转义
echo \"Hello AC Terminal\"
echo "-----------------------------------"
# 显示变量
name=yxc
echo "My name is $name"
echo "-----------------------------------"
# 显示换行
echo -e "Hi\n" # -e表示开启转义,\n换行
echo "acwing"
echo "-----------------------------------"
# 显示不换行
echo -e "Hi,\c" # -e表示开启转义,\c不换行
echo "acwing"
echo "-----------------------------------"
# 显示结果定向至文件
echo "Hello World!" > output.txt # 将内容以覆盖的方式输出到output.txt中
echo "-----------------------------------"
# 原样输出字符串,不进行转义或取变量(用单引号)
temp=cgw
echo '\"$temp\"'
echo "-----------------------------------"
# 显示命令的执行结果
echo `date`
echo $(date)
执行脚本
acs@80826ae841a9:~/temp$ ls
temp.cpp test.sh
acs@80826ae841a9:~/temp$ ./test.sh
Hello AC Terminal
Hello AC Terminal
-----------------------------------
"Hello AC Terminal"
"Hello AC Terminal"
-----------------------------------
My name is yxc
-----------------------------------
Hi
acwing
-----------------------------------
Hi,acwing
-----------------------------------
-----------------------------------
\"$temp\"
-----------------------------------
Sun Aug 13 15:34:41 CST 2023
Sun Aug 13 15:34:41 CST 2023
acs@80826ae841a9:~/temp$ ls
output.txt temp.cpp test.sh
acs@80826ae841a9:~/temp$ cat output.txt
Hello World!
acs@80826ae841a9:~/temp$
printf命令
- printf命令:用于格式化输出,类似于C/C++中的printf函数,默认不会在字符串末尾添加换行符
脚本内容如下
#! /bin/bash
printf "%10d.\n" 123 # 占10位,右对齐
printf "%-10.2f.\n" 123.125321 # 占10位,左对齐,保留2位小数(四舍五入)
printf "My name is %s\n" "yxc" # 格化输出字符串
printf "%d * %d = %d\n" 2 3 `expr 2 \* 3` # 表达式的值作为参数
执行脚本
acs@80826ae841a9:~/temp$ ./test.sh
123.
123.13 .
My name is yxc
2 * 3 = 6
acs@80826ae841a9:~/temp$
test命令
-
逻辑运算符&&和||
-
二者具有短路原则,我们可以利用短路原则来实现if else语句的作用
-
表达式的exit code(退出状态)为0表示真,为非0表示假(与C和C++中的定义相反)
-
-
test命令
- test命令用于:判断数值比较的结果、判断字符串比较的结果、判断文件的类型和权限
- test命令执行后本身不会在stdout中输出结果
- test命令的exit code(退出状态):0表示真,非0表示假
判断数值比较的结果,有如下参数(只能用于数值的比较)
- -eq(等于)
- -ne(不等于)
- -gt(大于)
- -lt(小于)
- -ge(大于等于)
- -le(小于等于)
脚本内容如下
#! /bin/bash
test 2 -lt 3 # 判断2小于3是否成立
echo $? # 输出上个命令的返回值,2小于3为真,返回0,所以输出0
执行脚本
acs@80826ae841a9:~/temp$ ./test.sh
0
acs@80826ae841a9:~/temp$
判断字符串比较的结果,有如下参数
- -z(判断字符串是否为空,如果为空,则返回true)
- -n(判断字符串是否非空,如果非空,则返回true(-n可以省略))
- ==(判断字符串是否相等)
- !=(判断字符串是否不相等)
acs@80826ae841a9:~/temp$ test -z "Hello"
acs@80826ae841a9:~/temp$ echo $?
1
acs@80826ae841a9:~/temp$ test -n "Hello"
acs@80826ae841a9:~/temp$ echo $?
0
acs@80826ae841a9:~/temp$ test "Hello" == "hello"
acs@80826ae841a9:~/temp$ echo $?
1
acs@80826ae841a9:~/temp$ test "Hello" != "hello"
acs@80826ae841a9:~/temp$ echo $?
0
acs@80826ae841a9:~/temp$
判断文件的类型,有如下参数
- -e(判断文件是否存在)
- -f(判断是否为文件)
- -d(判断是否为目录)
acs@80826ae841a9:~/temp$ ls
temp.cpp test.sh
acs@80826ae841a9:~/temp$
acs@80826ae841a9:~/temp$ test -e test.sh && echo "exist" || echo "Not exist"
exist
acs@80826ae841a9:~/temp$ test -e test2.sh && echo "exist" || echo "Not exist"
Not exist
acs@80826ae841a9:~/temp$ test -f test.sh && echo "yy" || echo "nn"
yy
acs@80826ae841a9:~/temp$ test -d test.sh && echo "yy" || echo "nn"
nn
acs@80826ae841a9:~/temp$
acs@80826ae841a9:~/temp$ test -e test.sh
acs@80826ae841a9:~/temp$ echo $?
0
acs@80826ae841a9:~/temp$ test -f test.sh
acs@80826ae841a9:~/temp$ echo $?
0
acs@80826ae841a9:~/temp$ test -d test.sh
acs@80826ae841a9:~/temp$ echo $?
1
acs@80826ae841a9:~/temp$
判断文件的权限,有如下参数
- -r(判断文件是否可读)
- -w(判断文件是否可写)
- -x(判断文件是否可执行)
- -s(判断是否为非空文件)
acs@80826ae841a9:~/temp$ ls -l
total 8
-rw-rw-r-- 1 acs acs 132 Aug 4 00:12 temp.cpp
-rwxrwxr-x 1 acs acs 147 Aug 13 17:10 test.sh
acs@80826ae841a9:~/temp$ test -r temp.cpp
acs@80826ae841a9:~/temp$ echo $?
0
acs@80826ae841a9:~/temp$ test -w temp.cpp
acs@80826ae841a9:~/temp$ echo $?
0
acs@80826ae841a9:~/temp$ test -x temp.cpp
acs@80826ae841a9:~/temp$ echo $?
1
acs@80826ae841a9:~/temp$ test -s temp.cpp
acs@80826ae841a9:~/temp$ echo $?
0
acs@80826ae841a9:~/temp$
- 多重条件判定,有如下参数
- -a(判断两个条件是否同时成立)
- -o(判断两个条件是否至少一个成立)
- !(取反)
acs@80826ae841a9:~/temp$ ls -l
total 8
-rw-rw-r-- 1 acs acs 132 Aug 4 00:12 temp.cpp
-rwxrwxr-x 1 acs acs 147 Aug 13 17:10 test.sh
acs@80826ae841a9:~/temp$ test -r temp.cpp -a -x temp.cpp # 判断temp.cpp是否可读并且可执行
acs@80826ae841a9:~/temp$ echo $?
1
acs@80826ae841a9:~/temp$ test -r temp.cpp -o -x temp.cpp # 判断temp.cpp是否可读或者可执行
acs@80826ae841a9:~/temp$ echo $?
0
acs@80826ae841a9:~/temp$ test ! -x temp.cpp # 判断temp.cpp是否不可执行
acs@80826ae841a9:~/temp$ echo $?
0
acs@80826ae841a9:~/temp$
判断符号[]
判断符号[]与test命令的用法几乎一模一样
判断符号[]更常用于if语句中
[[]]是[]的加强版,支持的特性更多
注意事项:
- []内的每一项都要用空格隔开
- []内的变量,最好用双引号括起来
- []内的常数,最好用单引号或双引号括起来
acs@80826ae841a9:~/temp$ [ 2 -lt 3 ] # 为真,返回值为0
acs@80826ae841a9:~/temp$ echo $?
0
acs@80826ae841a9:~/temp$ ls
temp.cpp test.sh
acs@80826ae841a9:~/temp$ [ -e test.sh ] # 为真,返回值为0
acs@80826ae841a9:~/temp$ echo $?
0
acs@80826ae841a9:~/temp$ name="acwing yxc"
acs@80826ae841a9:~/temp$ [ "$name" == "acwing yxc" ]
acs@80826ae841a9:~/temp$ echo $?
0
acs@80826ae841a9:~/temp$
判断语句
-
单层if
-
脚本内容如下
#! /bin/bash a=3 b=4 if [ "$a" -lt "$b" ] && [ "$a" -gt 2 ] then echo ${a}在范围内 fi
-
执行脚本
acs@80826ae841a9:~/temp$ ls temp.cpp test.sh acs@80826ae841a9:~/temp$ ./test.sh 3在范围内 acs@80826ae841a9:~/temp$
-
-
单层if else
-
脚本内容如下
#! /bin/bash a=3 b=4 if ! [ "$a" -lt "$b" ] then echo ${a}不小于${b} else echo ${a}小于${b} fi
-
执行脚本
acs@80826ae841a9:~/temp$ ./test.sh 3小于4 acs@80826ae841a9:~/temp$
-
-
多层if elif elif else
-
脚本内容如下
#! /bin/bash a=4 if [ "$a" -eq 1 ] then echo ${a}等于1 elif [ "$a" -eq 2 ] then echo ${a}等于2 elif [ "$a" -eq 3 ] then echo ${a}等于3 else echo ${a}等于4 fi
-
执行脚本
acs@80826ae841a9:~/temp$ ./test.sh 4等于4 acs@80826ae841a9:~/temp$
-
-
case esac形式,类似于C和C++中的switch语句
-
脚本内容如下
#! /bin/bash a=4 case "$a" in 1) echo ${a}等于1 # 语句1 # 语句2 # 语句3 # ...... ;; # 类似于C和C++中的break 2) echo ${a}等于2 ;; 3) echo ${a}等于3 ;; *) # 类似于C和C++中的default echo ${a}等于其它数 ;; esac
-
执行脚本
acs@80826ae841a9:~/temp$ ./test.sh 4等于其它数 acs@80826ae841a9:~/temp$
-
循环语句
-
for…in…do…done
-
示例一:脚本内容如下
#! /bin/bash for i in a 2 cc do echo ${i} done
-
执行脚本
acs@80826ae841a9:~/temp$ ./test.sh a 2 cc acs@80826ae841a9:~/temp$
-
示例二:脚本内容如下
#! /bin/bash for file in `ls` do echo ${file} done
-
执行脚本
acs@80826ae841a9:~/temp$ ls temp.cpp test.sh acs@80826ae841a9:~/temp$ ./test.sh temp.cpp test.sh acs@80826ae841a9:~/temp$
-
示例三:脚本内容如下
#! /bin/bash # `seq 1 10`会返回用回车隔开的1到10 for i in `seq 1 10` do echo ${i} done
-
执行脚本
acs@80826ae841a9:~/temp$ ./test.sh 1 2 3 4 5 6 7 8 9 10 acs@80826ae841a9:~/temp$
-
示例四:脚本内容如下
#! /bin/bash for i in {1..10} do echo ${i} done echo "----------------------" for i in {a..z} do echo ${i} done
-
执行脚本
acs@80826ae841a9:~/temp$ ./test.sh 1 2 3 4 5 6 7 8 9 10 ---------------------- a b c d e f g h i j k l m n o p q r s t u v w x y z acs@80826ae841a9:~/temp$
-
-
for ((…;…;…)) do…done
-
脚本内容如下
#! /bin/bash for ((i=1; i<=10; i++)) do echo ${i} done
-
执行脚本
acs@80826ae841a9:~/temp$ ./test.sh 1 2 3 4 5 6 7 8 9 10 acs@80826ae841a9:~/temp$
-
-
while…do…done
文件结束符为键盘按下CTRL + d,输入文件结束符后read命令的退出状态(exit code)为1
-
脚本内容如下
#! /bin/bash while read name do echo "上一条read命令的exit code为:${?}" echo "-------------------------------" echo "输入的字符或字符串为:${name}" echo "-------------------------------" done
-
执行脚本
acs@80826ae841a9:~/temp$ ./test.sh yxc 上一条read命令的exit code为:0 ------------------------------- 输入的字符或字符串为:yxc ------------------------------- cgw 上一条read命令的exit code为:0 ------------------------------- 输入的字符或字符串为:cgw ------------------------------- acs@80826ae841a9:~/temp$
-
-
until…do…done
先执行do…done中的命令,再进行判断
注意:当判断条件为真时会结束循环,判断条件为假时会继续循环!!!跟一般的循环语句的判断条件反着来的!!!
-
脚本内容如下
#! /bin/bash # 当用户读入yes或者YES时,判断条件为真,结束循环,否则一直等待读入 until [ "${word}" == "yes" ] || [ "${word}" == "YES" ] do read -p "Please input yes/YES to stop this program:" word done
-
执行脚本
acs@80826ae841a9:~/temp$ ./test.sh Please input yes/YES to stop this program:yES Please input yes/YES to stop this program:yeS Please input yes/YES to stop this program:yes acs@80826ae841a9:~/temp$ ./test.sh Please input yes/YES to stop this program:Yes Please input yes/YES to stop this program:YEs Please input yes/YES to stop this program:YES acs@80826ae841a9:~/temp$
-
-
break
跳出当前这一层的循环
注意:与C/C++不同的是,break不能跳出case语句
-
脚本内容如下
#! /bin/bash # 每次读入非结束符的字符串或字符时,会输出一遍1~7 while read name do for ((i=1; i<=10; i++)) do case ${i} in 8) break;# 跳出的是for循环,而不是case语句 ;; *) echo ${i} ;; esac done done
-
执行脚本
acs@80826ae841a9:~/temp$ ./test.sh yxc 1 2 3 4 5 6 7 cgw 1 2 3 4 5 6 7 acs@80826ae841a9:~/temp$
-
-
continue
跳出当前这次循环,直接进入下一次循环
-
脚本内容如下
#! /bin/bash # 输出1~10中的奇数 for ((i=1; i<=10; i++)) do if [ `expr ${i} % 2` -eq 0 ] then continue fi echo ${i} done
-
执行脚本
acs@80826ae841a9:~/temp$ ./test.sh 1 3 5 7 9 acs@80826ae841a9:~/temp$
-
死循环的处理方式
- 如果可以打开该程序,则键盘按下CTRL + c即可
- 如果无法打开该程序,则
- 使用top命令找到进程的PID
- 使用kill -9 PID命令即可强制关掉此进程
函数
bash中的函数类似于C/C++中的函数,但是bash中的函数return的返回值与C/C++的不同,bash中的函数return的返回值是exit code,取值为0~255,0表示正常结束
bash中的函数return的返回值可以通过${?}来获取
如果想获取bash中的函数的某些输出结果,可以把这些输出结果通过在函数中的echo输出到stdout中,然后通过 $(函数名) 或者 `函数名` 来截取获得stdout中的结果
-
不获取return值和stdout值
-
脚本内容如下
#! /bin/bash function func() { # function关键字可以省略 name=yxc echo "Hello ${name}" # 当函数中不写return时,则默认写了return 0 } func # 调用函数
-
执行脚本
acs@80826ae841a9:~/temp$ ./test.sh Hello yxc acs@80826ae841a9:~/temp$
-
-
获取return值和stdout值
-
脚本内容如下
#! /bin/bash func() { name=yxc echo "Hello ${name}" return 123 # 注意数值范围在0~255 } output=`func` # 截取获得函数中的echo输出到stdout中的结果,赋值给output变量 ret=${?} echo "output = ${output}" echo "return = ${ret}"
-
执行脚本
# 注意!!!执行脚本的结果为这个!!! acs@80826ae841a9:~/temp$ ./test.sh output = Hello yxc return = 123 acs@80826ae841a9:~/temp$ # 而不是我想象中的这个!!! # acs@80826ae841a9:~/temp$ ./test.sh # Hello yxc # output = Hello yxc # return = 123 # acs@80826ae841a9:~/temp$
-
-
函数的输入参数
在函数内, 1 表示第一个输入参数, {1}表示第一个输入参数, 1表示第一个输入参数,{2}表示第二个输入参数,依此类推
注意:函数内的${0}仍然是文件名,而不是函数名
-
脚本内容如下
-
简单递归的版本
#! /bin/bash func() { if [ ${1} -le 0 ] # 当函数的第一个输入参数小于等于0时,则结束递归 then echo 0 return 0 fi # 递归计算 10 + 9 + 8 + ... + 2 + 1 + 0 的值 sum=$(func $(expr ${1} - 1)) echo $(expr ${1} + ${sum}) } echo `func 10`
-
可以控制递归的版本,可以有效防止递归发生死循环
#! /bin/bash func() { word="" while [ "${word}" != 'y' ] && [ "${word}" != 'n' ] do read -p "要进入func(${1})函数吗?请输入y/n:" word done if [ "${word}" == 'n' ] then echo 0 return 0 # 函数正常退出 fi if [ ${1} -le 0 ] # 当函数的第一个输入参数小于等于0时,则结束递归 then echo 0 return 0 # 函数正常退出 fi # 递归计算 10 + 9 + 8 + ... + 2 + 1 + 0 的值 sum=$(func $(expr ${1} - 1)) echo `expr ${1} + ${sum}` } echo `func 10` # 截取获得函数中的echo输出到stdout中的结果,然后再执行这一行的echo
-
-
执行脚本
acs@80826ae841a9:~/temp$ ./test.sh 要进入func(10)函数吗?请输入y/n:y 要进入func(9)函数吗?请输入y/n:y 要进入func(8)函数吗?请输入y/n:y 要进入func(7)函数吗?请输入y/n:y 要进入func(6)函数吗?请输入y/n:y 要进入func(5)函数吗?请输入y/n:y 要进入func(4)函数吗?请输入y/n:y 要进入func(3)函数吗?请输入y/n:y 要进入func(2)函数吗?请输入y/n:y 要进入func(1)函数吗?请输入y/n:y 要进入func(0)函数吗?请输入y/n:y 55 acs@80826ae841a9:~/temp$ acs@80826ae841a9:~/temp$ ./test.sh 要进入func(10)函数吗?请输入y/n:y 要进入func(9)函数吗?请输入y/n:y 要进入func(8)函数吗?请输入y/n:y 要进入func(7)函数吗?请输入y/n:y 要进入func(6)函数吗?请输入y/n:y 要进入func(5)函数吗?请输入y/n:y 要进入func(4)函数吗?请输入y/n:y 要进入func(3)函数吗?请输入y/n:y 要进入func(2)函数吗?请输入y/n:n 52 acs@80826ae841a9:~/temp$
-
-
函数内的局部变量
可以在函数内定义局部变量,局部变量作用范围仅在当前函数内
可以在递归函数中定义局部变量
-
示例一:脚本内容如下
#! /bin/bash func() { local name=yxc # 局部变量,作用范围在当前函数内 echo "Name is ${name}" } func echo "<<<${name}>>>"
-
执行脚本
acs@80826ae841a9:~/temp$ ./test.sh Name is yxc <<<>>> acs@80826ae841a9:~/temp$
-
示例二:脚本内容如下
#! /bin/bash func() { name=yxc echo "Name is ${name}" } func echo "<<<${name}>>>"
-
执行脚本
acs@80826ae841a9:~/temp$ ./test.sh Name is yxc <<<yxc>>> acs@80826ae841a9:~/temp$
-
exit命令
exit命令用于退出当前shell进程,并返回一个退出状态的值,使用${?}可以接收这个退出状态的值
exit命令可以接受一个整数值作为参数,表示退出状态的值,如果不指定,则退出状态的值默认为0
exit命令退出状态的值只能是0~255之间的整数,其中只有0表示成功(正常退出),其它值都表示失败(非正常退出)
脚本内容如下
#! /bin/bash
if [ ${#} -ne 1 ]
then
echo "传入参数的个数不等于1"
exit 1
else
echo "传入参数的个数等于1"
# exit 和 exit 0 的效果一样
# exit
exit 0
fi
执行脚本
acs@80826ae841a9:~/temp$ ./test.sh
传入参数的个数不等于1
acs@80826ae841a9:~/temp$ echo ${?}
1
acs@80826ae841a9:~/temp$ ./test.sh acwing
传入参数的个数等于1
acs@80826ae841a9:~/temp$ echo ${?}
0
acs@80826ae841a9:~/temp$
文件重定向
每个进程默认都会打开3个文件
- stdin(标准输入),从命令行读取数据,文件描述符为0
- stdout(标准输出),向命令行输出数据,文件描述符为1
- stderr(标准错误输出),向命令行输出数据,文件描述符为2
可以用文件重定向将这3个文件重定向到其它文件中
重定向命令
-
command < file:将stdin重定向到file中,即从file中读取内容
-
command > file:将stdout重定向到file中
-
command >> file:将stdout以追加方式重定向到file中
-
command n> file:将文件描述符n重定向到file中
-
command n>> file:将文件描述符n以追加方式重定向到file中
-
示例一:
acs@80826ae841a9:~/temp$ ls temp.cpp test.sh acs@80826ae841a9:~/temp$ ls > output.txt acs@80826ae841a9:~/temp$ ls output.txt temp.cpp test.sh acs@80826ae841a9:~/temp$ cat output.txt output.txt temp.cpp test.sh acs@80826ae841a9:~/temp$
-
示例二:
脚本内容如下:
#! /bin/bash echo -e "Hello \c" > output.txt # 将stdout重定向到output.txt中 echo "World" >> output.txt # 将stdout以追加方式重定向到output.txt中 read str < output.txt # 从output.txt中读取内容 echo ${str}
执行脚本:
acs@80826ae841a9:~/temp$ ls output.txt temp.cpp test.sh acs@80826ae841a9:~/temp$ cat output.txt output.txt temp.cpp test.sh acs@80826ae841a9:~/temp$ ./test.sh Hello World acs@80826ae841a9:~/temp$ cat output.txt Hello World acs@80826ae841a9:~/temp$
-
示例三:
脚本内容如下:
#! /bin/bash read a read b echo `expr ${a} + ${b}`
执行脚本:
acs@80826ae841a9:~/temp$ ls input.txt temp.cpp test.sh acs@80826ae841a9:~/temp$ cat input.txt 3 4 acs@80826ae841a9:~/temp$ ./test.sh < input.txt > output.txt # 从input.txt中读取内容,将stdout重定向到output.txt中 acs@80826ae841a9:~/temp$ cat output.txt 7 acs@80826ae841a9:~/temp$
引入外部脚本
类似于C/C++中的include操作,bash也可以引入其它文件中的代码
脚本内容如下:
#! /bin/bash
# 第一种写法,引入temp.sh文件,引入的文件只要有可读权限即可
# source temp.sh
# 第二种写法,引入temp.sh文件,引入的文件只要有可读权限即可
. temp.sh
echo "My name is:${name}" # 可以使用temp.sh文件中的变量
执行脚本:
acs@80826ae841a9:~/temp$ ls
temp.cpp temp.sh test.sh
acs@80826ae841a9:~/temp$ cat temp.sh
#! /bin/bash
name=yxc
acs@80826ae841a9:~/temp$ ./test.sh
My name is:yxc
acs@80826ae841a9:~/temp$
ssh
ssh登录
-
登录远程服务器
acs@80826ae841a9:~$ pwd /home/acs acs@80826ae841a9:~$ ls -al total 148 drwxr-xr-x 1 acs acs 4096 Sep 19 00:19 . drwxr-xr-x 1 root root 4096 Jul 23 2021 .. -rw------- 1 acs acs 8493 Sep 18 23:56 .bash_history -rw-r--r-- 1 acs acs 220 Jul 23 2021 .bash_logout -rw-r--r-- 1 acs acs 3831 May 15 16:17 .bashrc drwx------ 2 acs acs 4096 Jul 24 23:17 .cache drwx------ 3 acs acs 4096 Jul 27 00:09 .config drwxrwxr-x 1 acs acs 4096 Jul 27 22:59 .homework drwxr-xr-x 1 acs acs 4096 Jul 23 2021 .ipython -rw-r--r-- 1 acs acs 807 Jul 23 2021 .profile -rw------- 1 acs acs 7 Aug 17 2021 .python_history drwx------ 1 acs acs 4096 Sep 19 00:19 .ssh -rw-r--r-- 1 acs acs 0 Jul 23 2021 .sudo_as_admin_successful -rw-r--r-- 1 acs acs 1569 May 15 16:17 .tmux.conf drwxr-xr-x 1 acs acs 4096 Sep 9 2021 .vim -rw------- 1 acs acs 50595 Sep 19 00:19 .viminfo -rw-r--r-- 1 acs acs 6128 May 15 16:17 .vimrc drwxrwxr-x 6 acs acs 4096 Sep 18 23:42 homework drwxrwxr-x 2 acs acs 4096 Sep 6 00:09 temp acs@80826ae841a9:~$ cd .ssh acs@80826ae841a9:~/.ssh$ ls # 此时该目录下还没有任何的文件 acs@80826ae841a9:~/.ssh$ acs@80826ae841a9:~/.ssh$ acs@80826ae841a9:~/.ssh$ acs@80826ae841a9:~/.ssh$ homework 4 getinfo # 先获取需要登录的远程服务器的信息 User: acs_11511 # 需要登录的远程服务器的某个用户名 HostName: 123.57.67.128 # IP地址或域名 Password: ******** # 密码(此处密码已经手动屏蔽) acs@80826ae841a9:~/.ssh$ acs@80826ae841a9:~/.ssh$ acs@80826ae841a9:~/.ssh$ acs@80826ae841a9:~/.ssh$ ssh acs_11511@123.57.67.128 -p 22 # 默认登录的端口号为22,命令中的"-p 22"可省略,除非想登录指定的端口号 The authenticity of host '123.57.67.128 (123.57.67.128)' can't be established. ECDSA key fingerprint is SHA256:El+Pj10jXvbx4RWsVgvKj1qY6N4qTBTk0AGc7a87r0k. Are you sure you want to continue connecting (yes/no/[fingerprint])? yes # 第一次登录某个远程服务器时会出现的提醒信息,直接输入yes Warning: Permanently added '123.57.67.128' (ECDSA) to the list of known hosts. acs_11511@123.57.67.128's password: # 直接输入密码 Welcome to AC Server * Tutorial: https://www.acwing.com/activity/content/57/ __ __________ __ ______ ___ _______ / \ / ______/ / \ \| || \ | |/ _____| / /\ \ | | | | /\ | || || \ \| || / ___ / /__\ \| | | | / \ | || || |\ \ || | |_ | / ______ \ \_____\ \/ /\ \/ /| || | \ || \____| | /_/ \_\_______\__/ \__/ |_||_| \_|\________/ acs_11511@acs:~$ # 此时已经成功登录到远程服务器,当前用户名为acs_11511 acs_11511@acs:~$ acs_11511@acs:~$ acs_11511@acs:~$ acs_11511@acs:~$ exit # 使用exit命令或者键盘按下CTRL + d,可以直接退出登录的远程服务器 logout Connection to 123.57.67.128 closed. acs@80826ae841a9:~/.ssh$ acs@80826ae841a9:~/.ssh$ acs@80826ae841a9:~/.ssh$ acs@80826ae841a9:~/.ssh$ pwd /home/acs/.ssh acs@80826ae841a9:~/.ssh$ ls # 此时该目录下发现多了一个文件known_hosts,该文件用于记录登录的远程服务器的信息 known_hosts acs@80826ae841a9:~/.ssh$
-
通过配置文件,可以简化ssh连接远程服务器操作
acs@80826ae841a9:~/.ssh$ homework 4 getinfo User: acs_11511 HostName: 123.57.67.128 Password: ******** # 密码(此处密码已经手动屏蔽) acs@80826ae841a9:~/.ssh$ pwd /home/acs/.ssh acs@80826ae841a9:~/.ssh$ ls known_hosts acs@80826ae841a9:~/.ssh$ vim config # 新建一个配置文件config acs@80826ae841a9:~/.ssh$ ls config known_hosts acs@80826ae841a9:~/.ssh$ cat config # 配置文件config内容如下,默认登录的端口号为22,可以省略,除非想登录指定的端口号 Host myserver Hostname 123.57.67.128 User acs_11511 Port 22 acs@80826ae841a9:~/.ssh$ ssh myserver # 现在使用ssh连接远程服务器时,可以直接使用别名myserver acs_11511@123.57.67.128's password: Welcome to AC Server * Tutorial: https://www.acwing.com/activity/content/57/ __ __________ __ ______ ___ _______ / \ / ______/ / \ \| || \ | |/ _____| / /\ \ | | | | /\ | || || \ \| || / ___ / /__\ \| | | | / \ | || || |\ \ || | |_ | / ______ \ \_____\ \/ /\ \/ /| || | \ || \____| | /_/ \_\_______\__/ \__/ |_||_| \_|\________/ acs_11511@acs:~$ acs_11511@acs:~$ acs_11511@acs:~$ acs_11511@acs:~$ exit logout Connection to 123.57.67.128 closed. acs@80826ae841a9:~/.ssh$
-
密钥登录
第一种方式
acs@80826ae841a9:~/.ssh$ pwd /home/acs/.ssh acs@80826ae841a9:~/.ssh$ ls config known_hosts acs@80826ae841a9:~/.ssh$ ssh-keygen # 通过这个命令可以直接创建密钥,命令执行后一直按回车即可 Generating public/private rsa key pair. Enter file in which to save the key (/home/acs/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/acs/.ssh/id_rsa Your public key has been saved in /home/acs/.ssh/id_rsa.pub The key fingerprint is: SHA256:TvU0i26amcku513ja138Hxq8drMJVj+o7VTC1mvNmKM acs@80826ae841a9 The key's randomart image is: +---[RSA 3072]----+ | | | | | . o | | . +.o. | | S . o+ = | | o . o =+*| | . o oO+*=| | ...O o*+B+=| | =X .oE*.o=| +----[SHA256]-----+ acs@80826ae841a9:~/.ssh$ ls # 此时该目录下发现多了两个文件id_rsa、id_rsa.pub。id_rsa为记录私钥信息的文件,id_rsa.pub为记录公钥信息的文件 config id_rsa id_rsa.pub known_hosts acs@80826ae841a9:~/.ssh$ cat id_rsa.pub # 把id_rsa.pub记录的公钥信息,复制到需要登录的远程服务器的~/.ssh/authorized_keys文件中 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC1TTXGpAqNKUt3AbtH85pOEUQTVNBx9dqmXcwUxRd++JaagGY8q1OkTQ/1Aojq/dGmKzM4F1Vdlz61w5QBoGqlqe71OwTLT0Iq4GLSkRNyl5C02vw/INOefRSmAD75RUAisT2Kto++pXJCQ+xJQXejduzjVKY0jZDqT4ijsuRw1tUpx4fM4GGKwfgKyJ5ff1Ucq/9b3m0CCOFdYKQd0pBPL8zVUJhCmSc/pjWTPYqE8zuC0LkvVpnAomeN3TAacJtSwb8lUR4Sb7S1L4PSetdU0O1KX6Rri3BW6+L8CU5q8YPMGrpTAwMZPBK8Xq491mRr0T9OVbPTqcGnUJRHvBjMwbk2MMkOHZj0g/LWkWVT7N9jj7/esdTVfknfBiY9DHQMUu5+eTUOwKQlXTs3L05FXGu5/5YBdH9zdbA4nm5qeLUlyRSPmk2uvE171zGoJ4ExXyLS79wBPKkO033Kkusvicun7bLAaUJugxozBrER1sF2hHZlVFKRoK6TeIPB9O8= acs@80826ae841a9 acs@80826ae841a9:~/.ssh$ acs@80826ae841a9:~/.ssh$ acs@80826ae841a9:~/.ssh$ acs@80826ae841a9:~/.ssh$ ssh myserver acs_11511@123.57.67.128's password: Welcome to AC Server * Tutorial: https://www.acwing.com/activity/content/57/ __ __________ __ ______ ___ _______ / \ / ______/ / \ \| || \ | |/ _____| / /\ \ | | | | /\ | || || \ \| || / ___ / /__\ \| | | | / \ | || || |\ \ || | |_ | / ______ \ \_____\ \/ /\ \/ /| || | \ || \____| | /_/ \_\_______\__/ \__/ |_||_| \_|\________/ acs_11511@acs:~$ pwd /home/acs_11511 acs_11511@acs:~$ ls -al total 288 drwxr-xr-x 3 acs_11511 acs_11511 4096 Sep 19 00:14 . drwxr-xr-x 9002 root root 266240 Dec 12 2022 .. -rw------- 1 acs_11511 acs_11511 30 Sep 24 23:14 .bash_history -rw-r--r-- 1 acs_11511 acs_11511 220 Dec 11 2022 .bash_logout -rw-r--r-- 1 acs_11511 acs_11511 3771 Dec 11 2022 .bashrc drwx------ 2 acs_11511 acs_11511 4096 Sep 18 23:56 .cache -rw-r--r-- 1 acs_11511 acs_11511 807 Dec 11 2022 .profile acs_11511@acs:~$ mkdir .ssh acs_11511@acs:~$ ls -al total 300 drwxr-xr-x 4 acs_11511 acs_11511 4096 Sep 24 23:26 . drwxr-xr-x 9002 root root 266240 Dec 12 2022 .. -rw------- 1 acs_11511 acs_11511 187 Sep 24 23:23 .bash_history -rw-r--r-- 1 acs_11511 acs_11511 220 Dec 11 2022 .bash_logout -rw-r--r-- 1 acs_11511 acs_11511 3771 Dec 11 2022 .bashrc drwx------ 2 acs_11511 acs_11511 4096 Sep 18 23:56 .cache -rw-r--r-- 1 acs_11511 acs_11511 807 Dec 11 2022 .profile drwxrwxr-x 2 acs_11511 acs_11511 4096 Sep 24 23:26 .ssh -rw------- 1 acs_11511 acs_11511 4498 Sep 24 23:26 .viminfo acs_11511@acs:~$ cd .ssh/ acs_11511@acs:~/.ssh$ ls acs_11511@acs:~/.ssh$ vim authorized_keys acs_11511@acs:~/.ssh$ ls authorized_keys acs_11511@acs:~/.ssh$ cat authorized_keys ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC1TTXGpAqNKUt3AbtH85pOEUQTVNBx9dqmXcwUxRd++JaagGY8q1OkTQ/1Aojq/dGmKzM4F1Vdlz61w5QBoGqlqe71OwTLT0Iq4GLSkRNyl5C02vw/INOefRSmAD75RUAisT2Kto++pXJCQ+xJQXejduzjVKY0jZDqT4ijsuRw1tUpx4fM4GGKwfgKyJ5ff1Ucq/9b3m0CCOFdYKQd0pBPL8zVUJhCmSc/pjWTPYqE8zuC0LkvVpnAomeN3TAacJtSwb8lUR4Sb7S1L4PSetdU0O1KX6Rri3BW6+L8CU5q8YPMGrpTAwMZPBK8Xq491mRr0T9OVbPTqcGnUJRHvBjMwbk2MMkOHZj0g/LWkWVT7N9jj7/esdTVfknfBiY9DHQMUu5+eTUOwKQlXTs3L05FXGu5/5YBdH9zdbA4nm5qeLUlyRSPmk2uvE171zGoJ4ExXyLS79wBPKkO033Kkusvicun7bLAaUJugxozBrER1sF2hHZlVFKRoK6TeIPB9O8= acs@80826ae841a9 acs_11511@acs:~/.ssh$ exit logout Connection to 123.57.67.128 closed. acs@80826ae841a9:~/.ssh$ acs@80826ae841a9:~/.ssh$ acs@80826ae841a9:~/.ssh$ acs@80826ae841a9:~/.ssh$ ssh myserver # 此时即可通过密钥直接登录远程服务器,而不需要输入密码 Welcome to AC Server * Tutorial: https://www.acwing.com/activity/content/57/ __ __________ __ ______ ___ _______ / \ / ______/ / \ \| || \ | |/ _____| / /\ \ | | | | /\ | || || \ \| || / ___ / /__\ \| | | | / \ | || || |\ \ || | |_ | / ______ \ \_____\ \/ /\ \/ /| || | \ || \____| | /_/ \_\_______\__/ \__/ |_||_| \_|\________/ acs_11511@acs:~$ exit logout Connection to 123.57.67.128 closed. acs@80826ae841a9:~/.ssh$
第二种方式
acs@80826ae841a9:~/.ssh$ pwd /home/acs/.ssh acs@80826ae841a9:~/.ssh$ ls config known_hosts acs@80826ae841a9:~/.ssh$ ssh-keygen # 通过这个命令可以直接创建密钥,命令执行后一直按回车即可 Generating public/private rsa key pair. Enter file in which to save the key (/home/acs/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/acs/.ssh/id_rsa Your public key has been saved in /home/acs/.ssh/id_rsa.pub The key fingerprint is: SHA256:TvU0i26amcku513ja138Hxq8drMJVj+o7VTC1mvNmKM acs@80826ae841a9 The key's randomart image is: +---[RSA 3072]----+ | | | | | . o | | . +.o. | | S . o+ = | | o . o =+*| | . o oO+*=| | ...O o*+B+=| | =X .oE*.o=| +----[SHA256]-----+ acs@80826ae841a9:~/.ssh$ ls # 此时该目录下发现多了两个文件id_rsa、id_rsa.pub。id_rsa为记录私钥信息的文件,id_rsa.pub为记录公钥信息的文件 config id_rsa id_rsa.pub known_hosts acs@80826ae841a9:~/.ssh$ cat id_rsa.pub ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC1TTXGpAqNKUt3AbtH85pOEUQTVNBx9dqmXcwUxRd++JaagGY8q1OkTQ/1Aojq/dGmKzM4F1Vdlz61w5QBoGqlqe71OwTLT0Iq4GLSkRNyl5C02vw/INOefRSmAD75RUAisT2Kto++pXJCQ+xJQXejduzjVKY0jZDqT4ijsuRw1tUpx4fM4GGKwfgKyJ5ff1Ucq/9b3m0CCOFdYKQd0pBPL8zVUJhCmSc/pjWTPYqE8zuC0LkvVpnAomeN3TAacJtSwb8lUR4Sb7S1L4PSetdU0O1KX6Rri3BW6+L8CU5q8YPMGrpTAwMZPBK8Xq491mRr0T9OVbPTqcGnUJRHvBjMwbk2MMkOHZj0g/LWkWVT7N9jj7/esdTVfknfBiY9DHQMUu5+eTUOwKQlXTs3L05FXGu5/5YBdH9zdbA4nm5qeLUlyRSPmk2uvE171zGoJ4ExXyLS79wBPKkO033Kkusvicun7bLAaUJugxozBrER1sF2hHZlVFKRoK6TeIPB9O8= acs@80826ae841a9 acs@80826ae841a9:~/.ssh$ ssh-copy-id myserver # 通过这个命令,可以直接实现把id_rsa.pub记录的公钥信息,复制到需要登录的远程服务器的~/.ssh/authorized_keys文件中 /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/acs/.ssh/id_rsa.pub" /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys acs_11511@123.57.67.128's password: Number of key(s) added: 1 Now try logging into the machine, with: "ssh 'myserver'" and check to make sure that only the key(s) you wanted were added. acs@80826ae841a9:~/.ssh$ acs@80826ae841a9:~/.ssh$ acs@80826ae841a9:~/.ssh$ acs@80826ae841a9:~/.ssh$ ssh myserver # 此时即可通过密钥直接登录远程服务器,而不需要输入密码 Welcome to AC Server * Tutorial: https://www.acwing.com/activity/content/57/ __ __________ __ ______ ___ _______ / \ / ______/ / \ \| || \ | |/ _____| / /\ \ | | | | /\ | || || \ \| || / ___ / /__\ \| | | | / \ | || || |\ \ || | |_ | / ______ \ \_____\ \/ /\ \/ /| || | \ || \____| | /_/ \_\_______\__/ \__/ |_||_| \_|\________/ acs_11511@acs:~$ pwd /home/acs_11511 acs_11511@acs:~$ ls -al total 300 drwxr-xr-x 4 acs_11511 acs_11511 4096 Sep 24 23:49 . drwxr-xr-x 9002 root root 266240 Dec 12 2022 .. -rw------- 1 acs_11511 acs_11511 275 Sep 24 23:48 .bash_history -rw-r--r-- 1 acs_11511 acs_11511 220 Dec 11 2022 .bash_logout -rw-r--r-- 1 acs_11511 acs_11511 3771 Dec 11 2022 .bashrc drwx------ 2 acs_11511 acs_11511 4096 Sep 18 23:56 .cache -rw-r--r-- 1 acs_11511 acs_11511 807 Dec 11 2022 .profile drwx------ 2 acs_11511 acs_11511 4096 Sep 24 23:49 .ssh -rw------- 1 acs_11511 acs_11511 4498 Sep 24 23:26 .viminfo acs_11511@acs:~$ cd .ssh/ acs_11511@acs:~/.ssh$ ls authorized_keys acs_11511@acs:~/.ssh$ cat authorized_keys ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC1TTXGpAqNKUt3AbtH85pOEUQTVNBx9dqmXcwUxRd++JaagGY8q1OkTQ/1Aojq/dGmKzM4F1Vdlz61w5QBoGqlqe71OwTLT0Iq4GLSkRNyl5C02vw/INOefRSmAD75RUAisT2Kto++pXJCQ+xJQXejduzjVKY0jZDqT4ijsuRw1tUpx4fM4GGKwfgKyJ5ff1Ucq/9b3m0CCOFdYKQd0pBPL8zVUJhCmSc/pjWTPYqE8zuC0LkvVpnAomeN3TAacJtSwb8lUR4Sb7S1L4PSetdU0O1KX6Rri3BW6+L8CU5q8YPMGrpTAwMZPBK8Xq491mRr0T9OVbPTqcGnUJRHvBjMwbk2MMkOHZj0g/LWkWVT7N9jj7/esdTVfknfBiY9DHQMUu5+eTUOwKQlXTs3L05FXGu5/5YBdH9zdbA4nm5qeLUlyRSPmk2uvE171zGoJ4ExXyLS79wBPKkO033Kkusvicun7bLAaUJugxozBrER1sF2hHZlVFKRoK6TeIPB9O8= acs@80826ae841a9 acs_11511@acs:~/.ssh$ exit logout Connection to 123.57.67.128 closed. acs@80826ae841a9:~/.ssh$
-
执行命令
acs@80826ae841a9:~/.ssh$ pwd /home/acs/.ssh acs@80826ae841a9:~/.ssh$ ls -al total 28 drwx------ 1 acs acs 4096 Sep 24 23:49 . drwxr-xr-x 1 acs acs 4096 Sep 24 23:25 .. -rw-rw-r-- 1 acs acs 72 Sep 21 00:13 config -rw------- 1 acs acs 2602 Sep 24 23:03 id_rsa -rw-r--r-- 1 acs acs 570 Sep 24 23:25 id_rsa.pub -rw-r--r-- 1 acs acs 222 Sep 19 00:21 known_hosts acs@80826ae841a9:~/.ssh$ ssh myserver ls -al # 这个命令相当于,把在远程服务器端执行的ls -al命令的标准输出,重定向到当前终端 total 300 drwxr-xr-x 4 acs_11511 acs_11511 4096 Sep 24 23:49 . drwxr-xr-x 9002 root root 266240 Dec 12 2022 .. -rw------- 1 acs_11511 acs_11511 320 Sep 25 00:00 .bash_history -rw-r--r-- 1 acs_11511 acs_11511 220 Dec 11 2022 .bash_logout -rw-r--r-- 1 acs_11511 acs_11511 3771 Dec 11 2022 .bashrc drwx------ 2 acs_11511 acs_11511 4096 Sep 18 23:56 .cache -rw-r--r-- 1 acs_11511 acs_11511 807 Dec 11 2022 .profile drwx------ 2 acs_11511 acs_11511 4096 Sep 24 23:49 .ssh -rw------- 1 acs_11511 acs_11511 4498 Sep 24 23:26 .viminfo acs@80826ae841a9:~/.ssh$ ssh myserver 'for ((i=0;i<10;i++)) do echo ${i}; done' # 使用单引号正常显示结果。单引号在远程服务器进行解析,i的值在远程服务器随循环而变化 0 1 2 3 4 5 6 7 8 9 acs@80826ae841a9:~/.ssh$ ssh myserver "for ((i=0;i<10;i++)) do echo ${i}; done" # 使用双引号无法显示结果。双引号在本地服务器进行解析,本地服务器不知道i的值 acs@80826ae841a9:~/.ssh$
scp传文件
-
示例一
acs@80826ae841a9:~$ pwd /home/acs acs@80826ae841a9:~$ ls homework temp acs@80826ae841a9:~$ cd temp/ acs@80826ae841a9:~/temp$ ls temp.cpp temp.sh test.sh acs@80826ae841a9:~/temp$ cd .. acs@80826ae841a9:~$ scp -r temp/ myserver:/home/acs_11511/ # 把当前目录下的temp整个文件夹,传送到远程服务器的/home/acs_11511/目录下 .main.cpp.swp 100% 12KB 5.9MB/s 00:00 temp.cpp 100% 132 156.6KB/s 00:00 temp.sh 100% 23 24.8KB/s 00:00 test.sh 100% 68 93.2KB/s 00:00 .test.sh.swp 100% 12KB 12.7MB/s 00:00 acs@80826ae841a9:~$ ssh myserver Welcome to AC Server * Tutorial: https://www.acwing.com/activity/content/57/ __ __________ __ ______ ___ _______ / \ / ______/ / \ \| || \ | |/ _____| / /\ \ | | | | /\ | || || \ \| || / ___ / /__\ \| | | | / \ | || || |\ \ || | |_ | / ______ \ \_____\ \/ /\ \/ /| || | \ || \____| | /_/ \_\_______\__/ \__/ |_||_| \_|\________/ acs_11511@acs:~$ pwd /home/acs_11511 acs_11511@acs:~$ ls temp acs_11511@acs:~$ cd temp acs_11511@acs:~/temp$ ls temp.cpp temp.sh test.sh acs_11511@acs:~/temp$ exit logout Connection to 123.57.67.128 closed. acs@80826ae841a9:~$
-
示例二
acs@80826ae841a9:~$ pwd /home/acs acs@80826ae841a9:~$ ls homework acs@80826ae841a9:~$ scp -r myserver:/home/acs_11511/temp/ . # 把远程服务器的/home/acs_11511/目录下的temp整个文件夹,传送到当前目录下 .main.cpp.swp 100% 12KB 15.9MB/s 00:00 temp.cpp 100% 132 331.4KB/s 00:00 temp.sh 100% 23 54.4KB/s 00:00 test.sh 100% 68 169.8KB/s 00:00 .test.sh.swp 100% 12KB 20.4MB/s 00:00 acs@80826ae841a9:~$ ls homework temp acs@80826ae841a9:~$ cd temp/ acs@80826ae841a9:~/temp$ ls temp.cpp temp.sh test.sh acs@80826ae841a9:~/temp$
-
示例三
acs@80826ae841a9:~/temp$ pwd /home/acs/temp acs@80826ae841a9:~/temp$ ls temp.cpp temp.sh test.sh acs@80826ae841a9:~/temp$ scp -P 22 temp.cpp temp.sh test.sh myserver:/home/acs_11511/ # 把当前目录下的这三个文件,传送到远程服务器的/home/acs_11511/目录下。命令中的"-P 22"可省略,除非想传送指定的端口号 temp.cpp 100% 132 87.0KB/s 00:00 temp.sh 100% 23 43.4KB/s 00:00 test.sh 100% 68 158.0KB/s 00:00 acs@80826ae841a9:~/temp$ ssh myserver Welcome to AC Server * Tutorial: https://www.acwing.com/activity/content/57/ __ __________ __ ______ ___ _______ / \ / ______/ / \ \| || \ | |/ _____| / /\ \ | | | | /\ | || || \ \| || / ___ / /__\ \| | | | / \ | || || |\ \ || | |_ | / ______ \ \_____\ \/ /\ \/ /| || | \ || \____| | /_/ \_\_______\__/ \__/ |_||_| \_|\________/ acs_11511@acs:~$ pwd /home/acs_11511 acs_11511@acs:~$ ls temp.cpp temp.sh test.sh acs_11511@acs:~$ exit logout Connection to 123.57.67.128 closed. acs@80826ae841a9:~/temp$
-
利用scp把.vimrc和.tmux.conf两个配置文件传送到远程服务器的/home/acs_11511/目录下,使远程服务器的vim和tmux的操作及其环境与AC Terminal一样
acs@80826ae841a9:~$ pwd /home/acs acs@80826ae841a9:~$ ls -al total 140 drwxr-xr-x 1 acs acs 4096 Sep 25 23:58 . drwxr-xr-x 1 root root 4096 Jul 23 2021 .. -rw------- 1 acs acs 9903 Sep 25 23:51 .bash_history -rw-r--r-- 1 acs acs 220 Jul 23 2021 .bash_logout -rw-r--r-- 1 acs acs 3831 May 15 16:17 .bashrc drwx------ 2 acs acs 4096 Jul 24 23:17 .cache drwx------ 3 acs acs 4096 Jul 27 00:09 .config drwxrwxr-x 1 acs acs 4096 Jul 27 22:59 .homework drwxr-xr-x 1 acs acs 4096 Jul 23 2021 .ipython -rw-r--r-- 1 acs acs 807 Jul 23 2021 .profile -rw------- 1 acs acs 7 Aug 17 2021 .python_history drwx------ 1 acs acs 4096 Sep 24 23:49 .ssh -rw-r--r-- 1 acs acs 0 Jul 23 2021 .sudo_as_admin_successful -rw-r--r-- 1 acs acs 1569 May 15 16:17 .tmux.conf drwxr-xr-x 1 acs acs 4096 Sep 9 2021 .vim -rw------- 1 acs acs 44297 Sep 25 23:58 .viminfo -rw-r--r-- 1 acs acs 6128 May 15 16:17 .vimrc drwxrwxr-x 6 acs acs 4096 Sep 18 23:42 homework drwxrwxr-x 2 acs acs 4096 Sep 25 23:30 temp acs@80826ae841a9:~$ scp .vimrc .tmux.conf myserver:/home/acs_11511/ .vimrc 100% 6128 2.7MB/s 00:00 .tmux.conf 100% 1569 3.5MB/s 00:00 acs@80826ae841a9:~$ ssh myserver Welcome to AC Server * Tutorial: https://www.acwing.com/activity/content/57/ __ __________ __ ______ ___ _______ / \ / ______/ / \ \| || \ | |/ _____| / /\ \ | | | | /\ | || || \ \| || / ___ / /__\ \| | | | / \ | || || |\ \ || | |_ | / ______ \ \_____\ \/ /\ \/ /| || | \ || \____| | /_/ \_\_______\__/ \__/ |_||_| \_|\________/ acs_11511@acs:~$ pwd /home/acs_11511 acs_11511@acs:~$ ls -al total 312 drwxr-xr-x 4 acs_11511 acs_11511 4096 Sep 25 23:58 . drwxr-xr-x 9002 root root 266240 Dec 12 2022 .. -rw------- 1 acs_11511 acs_11511 430 Sep 25 23:56 .bash_history -rw-r--r-- 1 acs_11511 acs_11511 220 Dec 11 2022 .bash_logout -rw-r--r-- 1 acs_11511 acs_11511 3771 Dec 11 2022 .bashrc drwx------ 2 acs_11511 acs_11511 4096 Sep 18 23:56 .cache -rw-r--r-- 1 acs_11511 acs_11511 807 Dec 11 2022 .profile drwx------ 2 acs_11511 acs_11511 4096 Sep 24 23:49 .ssh -rw-r--r-- 1 acs_11511 acs_11511 1569 Sep 25 23:58 .tmux.conf -rw------- 1 acs_11511 acs_11511 4498 Sep 24 23:26 .viminfo -rw-r--r-- 1 acs_11511 acs_11511 6128 Sep 25 23:58 .vimrc acs_11511@acs:~$ exit logout Connection to 123.57.67.128 closed. acs@80826ae841a9:~$
git
git的基本概念
- 工作区:仓库的目录
- 暂存区:数据暂时存放的区域,即工作区写入版本库前的缓存区
- 版本库:存放所有已经提交到本地仓库的代码版本
- 版本库结构:树结构,树中每个节点代表一个代码版本
git的常用命令-本地环境
- 设置全局用户名
- 设置全局邮箱地址
acs@80826ae841a9:~$ pwd
/home/acs
acs@80826ae841a9:~$ ls -al
total 148
drwxr-xr-x 1 acs acs 4096 Sep 26 21:58 .
drwxr-xr-x 1 root root 4096 Jul 23 2021 ..
-rw------- 1 acs acs 10240 Dec 21 00:05 .bash_history
-rw-r--r-- 1 acs acs 220 Jul 23 2021 .bash_logout
-rw-r--r-- 1 acs acs 3831 May 15 2023 .bashrc
drwx------ 2 acs acs 4096 Jul 24 23:17 .cache
drwx------ 3 acs acs 4096 Jul 27 00:09 .config
drwxrwxr-x 1 acs acs 4096 Jul 27 22:59 .homework
drwxr-xr-x 1 acs acs 4096 Jul 23 2021 .ipython
-rw-r--r-- 1 acs acs 807 Jul 23 2021 .profile
-rw------- 1 acs acs 7 Aug 17 2021 .python_history
drwx------ 1 acs acs 4096 Sep 26 20:50 .ssh
-rw-r--r-- 1 acs acs 0 Jul 23 2021 .sudo_as_admin_successful
-rw-r--r-- 1 acs acs 1569 May 15 2023 .tmux.conf
drwxr-xr-x 1 acs acs 4096 Sep 9 2021 .vim
-rw------- 1 acs acs 51664 Sep 26 21:58 .viminfo
-rw-r--r-- 1 acs acs 6128 May 15 2023 .vimrc
drwxrwxr-x 6 acs acs 4096 Sep 18 23:42 homework
drwxrwxr-x 2 acs acs 4096 Sep 25 23:30 temp
acs@80826ae841a9:~$ git config --global user.name cgw # 设置全局用户名
acs@80826ae841a9:~$ git config --global user.email qq398156587@163.com # 设置全局邮箱地址
acs@80826ae841a9:~$ ls -al
total 152
drwxr-xr-x 1 acs acs 4096 Dec 21 23:46 .
drwxr-xr-x 1 root root 4096 Jul 23 2021 ..
-rw------- 1 acs acs 10240 Dec 21 00:05 .bash_history
-rw-r--r-- 1 acs acs 220 Jul 23 2021 .bash_logout
-rw-r--r-- 1 acs acs 3831 May 15 2023 .bashrc
drwx------ 2 acs acs 4096 Jul 24 23:17 .cache
drwx------ 3 acs acs 4096 Jul 27 00:09 .config
-rw-rw-r-- 1 acs acs 48 Dec 21 23:46 .gitconfig # 信息记录在这个文件里面
drwxrwxr-x 1 acs acs 4096 Jul 27 22:59 .homework
drwxr-xr-x 1 acs acs 4096 Jul 23 2021 .ipython
-rw-r--r-- 1 acs acs 807 Jul 23 2021 .profile
-rw------- 1 acs acs 7 Aug 17 2021 .python_history
drwx------ 1 acs acs 4096 Sep 26 20:50 .ssh
-rw-r--r-- 1 acs acs 0 Jul 23 2021 .sudo_as_admin_successful
-rw-r--r-- 1 acs acs 1569 May 15 2023 .tmux.conf
drwxr-xr-x 1 acs acs 4096 Sep 9 2021 .vim
-rw------- 1 acs acs 51664 Sep 26 21:58 .viminfo
-rw-r--r-- 1 acs acs 6128 May 15 2023 .vimrc
drwxrwxr-x 6 acs acs 4096 Sep 18 23:42 homework
drwxrwxr-x 2 acs acs 4096 Sep 25 23:30 temp
acs@80826ae841a9:~$ cat .gitconfig
[user]
name = cgw
email = qq398156587@163.com
acs@80826ae841a9:~$
- 将当前目录配置成git仓库,信息记录在当前目录下隐藏的.git文件夹中
acs@80826ae841a9:~$ pwd
/home/acs
acs@80826ae841a9:~$ ls -l
total 8
drwxrwxr-x 6 acs acs 4096 Sep 18 23:42 homework
drwxrwxr-x 2 acs acs 4096 Sep 25 23:30 temp
acs@80826ae841a9:~$ mkdir project
acs@80826ae841a9:~$ ls -l
total 12
drwxrwxr-x 6 acs acs 4096 Sep 18 23:42 homework
drwxrwxr-x 2 acs acs 4096 Dec 21 23:52 project
drwxrwxr-x 2 acs acs 4096 Sep 25 23:30 temp
acs@80826ae841a9:~$ cd project/
acs@80826ae841a9:~/project$ ls -al
total 12
drwxrwxr-x 2 acs acs 4096 Dec 21 23:52 .
drwxr-xr-x 1 acs acs 4096 Dec 21 23:52 ..
acs@80826ae841a9:~/project$ git init # 将当前目录配置成git仓库
Initialized empty Git repository in /home/acs/project/.git/
acs@80826ae841a9:~/project$ ls -al
total 16
drwxrwxr-x 3 acs acs 4096 Dec 21 23:52 .
drwxr-xr-x 1 acs acs 4096 Dec 21 23:52 ..
drwxrwxr-x 7 acs acs 4096 Dec 21 23:52 .git # 信息记录在当前目录下隐藏的.git文件夹中
acs@80826ae841a9:~/project$ cd .git/
acs@80826ae841a9:~/project/.git$ ls -l
total 32
-rw-rw-r-- 1 acs acs 23 Dec 21 23:52 HEAD
drwxrwxr-x 2 acs acs 4096 Dec 21 23:52 branches
-rw-rw-r-- 1 acs acs 92 Dec 21 23:52 config
-rw-rw-r-- 1 acs acs 73 Dec 21 23:52 description
drwxrwxr-x 2 acs acs 4096 Dec 21 23:52 hooks
drwxrwxr-x 2 acs acs 4096 Dec 21 23:52 info
drwxrwxr-x 4 acs acs 4096 Dec 21 23:52 objects
drwxrwxr-x 4 acs acs 4096 Dec 21 23:52 refs
acs@80826ae841a9:~/project/.git$
- 查看仓库状态
- 将某个文件添加到暂存区
- 将暂存区的内容提交到当前分支
- 当工作区有改动,暂存区为空时,比较的是“工作区与最后一次提交到版本库的共同文件”的差别;当工作区有改动,暂存区不为空时,比较的是“工作区与暂存区的共同文件”的差别
- 将某个文件从暂存区中删掉,表示不管理这个文件
- 将某个文件从暂存区中删掉,但是仍然管理这个文件
acs@80826ae841a9:~/project$ pwd
/home/acs/project
acs@80826ae841a9:~/project$ ls -al
total 16
drwxrwxr-x 3 acs acs 4096 Dec 21 23:52 .
drwxr-xr-x 1 acs acs 4096 Dec 21 23:52 ..
drwxrwxr-x 7 acs acs 4096 Dec 21 23:52 .git
acs@80826ae841a9:~/project$ vim readme.txt
acs@80826ae841a9:~/project$ cat readme.txt
111
acs@80826ae841a9:~/project$ git status # 查看仓库状态
On branch master
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
readme.txt
nothing added to commit but untracked files present (use "git add" to track)
acs@80826ae841a9:~/project$ git add readme.txt # 将readme.txt文件添加到暂存区
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: readme.txt
# acs@80826ae841a9:~/project$ git add . # 将所有待加入暂存区的文件加入暂存区
acs@80826ae841a9:~/project$ git commit -m "cgw add readme.txt" # 将暂存区的内容提交到当前分支的下一个结点,可以添加备注信息
[master (root-commit) 76eeda8] cgw add readme.txt
1 file changed, 1 insertion(+)
create mode 100644 readme.txt
acs@80826ae841a9:~/project$ vim readme.txt # 修改下readme.txt文件的内容
acs@80826ae841a9:~/project$ cat readme.txt
111
222
acs@80826ae841a9:~/project$ git status # 查看仓库状态
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: readme.txt
no changes added to commit (use "git add" and/or "git commit -a")
acs@80826ae841a9:~/project$ git diff readme.txt # 当工作区有改动,暂存区为空时,比较的是“工作区与最后一次提交到版本库的共同文件”的差别;当工作区有改动,暂存区不为空时,比较的是“工作区与暂存区的共同文件”的差别
diff --git a/readme.txt b/readme.txt
index 58c9bdf..a30a52a 100644
--- a/readme.txt
+++ b/readme.txt
@@ -1 +1,2 @@
111
+222
acs@80826ae841a9:~/project$ git add readme.txt # 再将修改过内容的readme.txt文件添加到暂存区
acs@80826ae841a9:~/project$ git commit -m "cgw add 222" # 将暂存区的内容提交到当前分支的下一个结点
[master ca82a26] cgw add 222
1 file changed, 1 deletion(-)
acs@80826ae841a9:~/project$ vim readme.txt
acs@80826ae841a9:~/project$ cat readme.txt
111
222
333
acs@80826ae841a9:~/project$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: readme.txt
no changes added to commit (use "git add" and/or "git commit -a")
acs@80826ae841a9:~/project$ git add readme.txt # 再将修改过内容的readme.txt文件添加到暂存区
acs@80826ae841a9:~/project$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: readme.txt
acs@80826ae841a9:~/project$ git rm --cached readme.txt # 将readme.txt文件从暂存区中删掉,表示不管理readme.txt文件
rm 'readme.txt'
acs@80826ae841a9:~/project$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
deleted: readme.txt
Untracked files:
(use "git add <file>..." to include in what will be committed)
readme.txt
acs@80826ae841a9:~/project$ git add readme.txt # 要管理readme.txt文件时,再把它添加到暂存区即可
acs@80826ae841a9:~/project$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: readme.txt
acs@80826ae841a9:~/project$ git restore --staged readme.txt # 将readme.txt文件从暂存区中删掉,但是仍然管理readme.txt文件
acs@80826ae841a9:~/project$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: readme.txt
no changes added to commit (use "git add" and/or "git commit -a")
acs@80826ae841a9:~/project$ git add readme.txt
acs@80826ae841a9:~/project$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: readme.txt
acs@80826ae841a9:~/project$ git commit -m "cgw add 333" # 将暂存区的内容提交到当前分支的下一个结点
[master 344061a] cgw add 333
1 file changed, 1 insertion(+)
acs@80826ae841a9:~/project$
- 查看当前分支的所有版本
- 将代码库回滚到前面的版本
- 查看HEAD指针的移动历史(包括被回滚的版本)
- 当工作区有改动,暂存区为空时,将某个文件的修改回滚到“工作区与最后一次提交到版本库的共同文件”的版本;当工作区有改动,暂存区不为空时,将某个文件的修改回滚到“工作区与暂存区的共同文件”的版本
acs@80826ae841a9:~/project$ pwd
/home/acs/project
acs@80826ae841a9:~/project$ ls -l
total 4
-rw-rw-r-- 1 acs acs 12 Dec 30 16:33 readme.txt
acs@80826ae841a9:~/project$ git log # 查看当前分支的所有版本
commit 344061a8b36985b34d2fe2091b90e0447c10bbe1 (HEAD -> master)
Author: cgw <qq398156587@163.com>
Date: Sat Dec 30 16:49:16 2023 +0800
cgw add 333
commit ca82a26f5539e6f67888814e7405881bb9156db2
Author: cgw <qq398156587@163.com>
Date: Sat Dec 30 16:28:25 2023 +0800
cgw add 222
commit 76eeda86e7387e09ded53023286d6fdb637dcb87
Author: cgw <qq398156587@163.com>
Date: Sat Dec 30 15:54:56 2023 +0800
cgw add readme.txt
acs@80826ae841a9:~/project$ git log --pretty=oneline # 查看当前分支的所有版本,可以显示的好看一些
344061a8b36985b34d2fe2091b90e0447c10bbe1 (HEAD -> master) cgw add 333 # 344061a即为版本号
ca82a26f5539e6f67888814e7405881bb9156db2 cgw add 222 # ca82a26即为版本号
76eeda86e7387e09ded53023286d6fdb637dcb87 cgw add readme.txt # 76eeda8即为版本号
acs@80826ae841a9:~/project$ git reset --hard HEAD^^ # 将代码库回滚到前2个版本。有一个^就表示往前回滚1个版本,有两个^就表示往前回滚2个版本,以此类推
HEAD is now at 76eeda8 cgw add readme.txt
# acs@80826ae841a9:~/project$ git reset --hard HEAD~ # 将代码库回滚到前1个版本
# acs@80826ae841a9:~/project$ git reset --hard HEAD~100 # 将代码库回滚到前100个版本
# acs@80826ae841a9:~/project$ git reset --hard 版本号 # 根据版本号,将代码库回滚到指定的版本
acs@80826ae841a9:~/project$ git log # 查看当前分支的所有版本
commit 76eeda86e7387e09ded53023286d6fdb637dcb87 (HEAD -> master)
Author: cgw <qq398156587@163.com>
Date: Sat Dec 30 15:54:56 2023 +0800
cgw add readme.txt
acs@80826ae841a9:~/project$ git reflog # 查看HEAD指针的移动历史(包括被回滚的版本)
76eeda8 (HEAD -> master) HEAD@{0}: reset: moving to HEAD^^
344061a HEAD@{1}: commit: cgw add 333
ca82a26 HEAD@{2}: commit: cgw add 222
76eeda8 (HEAD -> master) HEAD@{3}: commit (initial): cgw add readme.txt
acs@80826ae841a9:~/project$ git reset --hard 344061a # 根据版本号,将代码库回滚到指定的版本
HEAD is now at 344061a cgw add 333
acs@80826ae841a9:~/project$ cat readme.txt
111
222
333
acs@80826ae841a9:~/project$ git reset --hard HEAD^^
HEAD is now at 76eeda8 cgw add readme.txt
acs@80826ae841a9:~/project$ cat readme.txt # 可以发现,版本回滚确实生效了
111
acs@80826ae841a9:~/project$ git reset --hard 344061a # 根据版本号,将代码库回滚到指定的版本
HEAD is now at 344061a cgw add 333
acs@80826ae841a9:~/project$ cat readme.txt
111
222
333
acs@80826ae841a9:~/project$ git status
On branch master
nothing to commit, working tree clean
acs@80826ae841a9:~/project$ vim readme.txt
acs@80826ae841a9:~/project$ cat readme.txt
111
222
333
444
acs@80826ae841a9:~/project$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: readme.txt
no changes added to commit (use "git add" and/or "git commit -a")
acs@80826ae841a9:~/project$ git restore readme.txt # 当工作区有改动,暂存区为空时,将readme.txt文件的修改回滚到“工作区与最后一次提交到版本库的共同文件”的版本;当工作区有改动,暂存区不为空时,将readme.txt文件的修改回滚到“工作区与暂存区的共同文件”的版本
acs@80826ae841a9:~/project$ git status
On branch master
nothing to commit, working tree clean
acs@80826ae841a9:~/project$ cat readme.txt
111
222
333
acs@80826ae841a9:~/project$ touch main.cpp
acs@80826ae841a9:~/project$ ls -l
total 4
-rw-rw-r-- 1 acs acs 0 Dec 30 18:33 main.cpp
-rw-rw-r-- 1 acs acs 12 Dec 30 17:58 readme.txt
acs@80826ae841a9:~/project$ git status
On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed)
main.cpp
nothing added to commit but untracked files present (use "git add" to track)
acs@80826ae841a9:~/project$ git add .
acs@80826ae841a9:~/project$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: main.cpp
acs@80826ae841a9:~/project$ vim readme.txt
acs@80826ae841a9:~/project$ cat readme.txt
111
222
333
666
acs@80826ae841a9:~/project$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: main.cpp
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: readme.txt
acs@80826ae841a9:~/project$ git add .
acs@80826ae841a9:~/project$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: main.cpp
modified: readme.txt
acs@80826ae841a9:~/project$ git commit -m "cgw add main.cpp"
[master f8ad874] cgw add main.cpp
2 files changed, 1 insertion(+)
create mode 100644 main.cpp
acs@80826ae841a9:~/project$ vim main.cpp
acs@80826ae841a9:~/project$ cat main.cpp
111
acs@80826ae841a9:~/project$ vim readme.txt
acs@80826ae841a9:~/project$ cat readme.txt
111
222
333
777
acs@80826ae841a9:~/project$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: main.cpp
modified: readme.txt
no changes added to commit (use "git add" and/or "git commit -a")
acs@80826ae841a9:~/project$ git add main.cpp
acs@80826ae841a9:~/project$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: main.cpp
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: readme.txt
acs@80826ae841a9:~/project$ git commit -m "cgw save main.cpp"
[master badf2d6] cgw save main.cpp
1 file changed, 1 insertion(+)
acs@80826ae841a9:~/project$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: readme.txt
no changes added to commit (use "git add" and/or "git commit -a")
acs@80826ae841a9:~/project$ git restore readme.txt
acs@80826ae841a9:~/project$ cat readme.txt
111
222
333
666
acs@80826ae841a9:~/project$ git status
On branch master
nothing to commit, working tree clean
acs@80826ae841a9:~/project$
- 可以把工作区中不小心删除的文件进行恢复,前提是这个文件曾经提交过到版本库中
acs@80826ae841a9:~/project$ pwd
/home/acs/project
acs@80826ae841a9:~/project$ ls -l
total 8
-rw-rw-r-- 1 acs acs 4 Dec 30 18:42 main.cpp
-rw-rw-r-- 1 acs acs 16 Dec 30 18:44 readme.txt
acs@80826ae841a9:~/project$ touch a.txt b.txt
acs@80826ae841a9:~/project$ ls -l
total 8
-rw-rw-r-- 1 acs acs 0 Dec 30 18:54 a.txt
-rw-rw-r-- 1 acs acs 0 Dec 30 18:54 b.txt
-rw-rw-r-- 1 acs acs 4 Dec 30 18:42 main.cpp
-rw-rw-r-- 1 acs acs 16 Dec 30 18:44 readme.txt
acs@80826ae841a9:~/project$ git status
On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed)
a.txt
b.txt
nothing added to commit but untracked files present (use "git add" to track)
acs@80826ae841a9:~/project$ git add .
acs@80826ae841a9:~/project$ git commit -m "cgw add a.txt b.txt"
[master 2165e17] cgw add a.txt b.txt
2 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 a.txt
create mode 100644 b.txt
acs@80826ae841a9:~/project$ git status
On branch master
nothing to commit, working tree clean
acs@80826ae841a9:~/project$ rm a.txt b.txt # 不小心删除的文件
acs@80826ae841a9:~/project$ git status
On branch master
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
deleted: a.txt
deleted: b.txt
no changes added to commit (use "git add" and/or "git commit -a")
acs@80826ae841a9:~/project$ git add a.txt b.txt # 把这两个文件的修改加入到暂存区中,对文件的删除也属于文件的修改
acs@80826ae841a9:~/project$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
deleted: a.txt
deleted: b.txt
acs@80826ae841a9:~/project$ ls -l
total 8
-rw-rw-r-- 1 acs acs 4 Dec 30 18:42 main.cpp
-rw-rw-r-- 1 acs acs 16 Dec 30 18:44 readme.txt
acs@80826ae841a9:~/project$ git restore --staged a.txt
acs@80826ae841a9:~/project$ git restore a.txt # 通过回滚,可以进行文件的恢复
acs@80826ae841a9:~/project$ ls -l
total 8
-rw-rw-r-- 1 acs acs 0 Dec 30 19:05 a.txt # 可以把a.txt文件恢复
-rw-rw-r-- 1 acs acs 4 Dec 30 18:42 main.cpp
-rw-rw-r-- 1 acs acs 16 Dec 30 18:44 readme.txt
acs@80826ae841a9:~/project$
-
将工作区和暂存区中尚未提交的修改存入栈中
-
查看栈中所有元素
-
将栈顶存储的修改恢复到当前分支,同时删除栈顶元素
-
将栈顶存储的修改恢复到当前分支,但不删除栈顶元素
git stash apply
-
删除栈顶存储的修改
git stash drop
acs@80826ae841a9:~/project$ git checkout -b dev6
Switched to a new branch 'dev6'
acs@80826ae841a9:~/project$ vim readme.txt # 修改readme.txt文件
acs@80826ae841a9:~/project$ git add readme.txt
acs@80826ae841a9:~/project$ vim readme.txt # 修改readme.txt文件
acs@80826ae841a9:~/project$ git status
On branch dev6
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: readme.txt
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: readme.txt
acs@80826ae841a9:~/project$ git stash # 将工作区和暂存区中尚未提交的修改存入栈中
Saved working directory and index state WIP on dev6: d165fff cgw add bbb
acs@80826ae841a9:~/project$ git stash list # 查看栈中所有元素
stash@{0}: WIP on dev6: d165fff cgw add bbb
acs@80826ae841a9:~/project$ git status
On branch dev6
nothing to commit, working tree clean
acs@80826ae841a9:~/project$ git checkout -b dev7
Switched to a new branch 'dev7'
acs@80826ae841a9:~/project$ vim readme.txt
acs@80826ae841a9:~/project$ git add readme.txt
acs@80826ae841a9:~/project$ git commit -m "fff"
[dev7 352675e] fff
1 file changed, 1 insertion(+)
acs@80826ae841a9:~/project$ git checkout master
Switched to branch 'master'
Your branch is up to date with 'origin/master'.
acs@80826ae841a9:~/project$ git merge dev7
Updating d165fff..352675e
Fast-forward
readme.txt | 1 +
1 file changed, 1 insertion(+)
acs@80826ae841a9:~/project$ git branch -d dev7
Deleted branch dev7 (was 352675e).
acs@80826ae841a9:~/project$ git checkout dev6
Switched to branch 'dev6'
acs@80826ae841a9:~/project$ git stash pop # 将栈顶存储的修改恢复到当前分支,同时删除栈顶元素
On branch dev6
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: readme.txt
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (f7e03d9dab8387e1ef228ff22acfafb409c3c5a3)
acs@80826ae841a9:~/project$
git的常用命令-云端环境
需要提前做好的准备工作:
1、先在代码管理平台(https://git.acwing.com/)注册账号,然后登录
2、新建一个项目,项目名字要和本地的项目名字一样
3、然后添加上本地服务器的ssh密钥的公钥信息,此时本地服务器即可通过ssh访问代码管理平台
- 将本地仓库关联到远程仓库
- 将本地的某个分支推送到远程仓库
acs@80826ae841a9:~/project$ pwd
/home/acs/project
acs@80826ae841a9:~/project$ ls -al
total 24
drwxrwxr-x 3 acs acs 4096 Dec 30 19:26 .
drwxr-xr-x 1 acs acs 4096 Dec 30 18:43 ..
drwxrwxr-x 8 acs acs 4096 Dec 30 20:36 .git
-rw-rw-r-- 1 acs acs 4 Dec 30 18:42 main.cpp
-rw-rw-r-- 1 acs acs 16 Dec 30 18:44 readme.txt
acs@80826ae841a9:~/project$ git remote add origin git@git.acwing.com:kkoyy459/project.git # 将本地仓库关联到远程仓库
acs@80826ae841a9:~/project$
acs@80826ae841a9:~/project$ git push origin master # 将本地的master分支推送到远程仓库
The authenticity of host 'git.acwing.com (47.93.222.173)' can't be established.
ECDSA key fingerprint is SHA256:OxENYBI4n6Nd8yOqmEdMazWuvBldKlP6ZJnOAAbCaeM.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes # 输入yes即可
Warning: Permanently added 'git.acwing.com,47.93.222.173' (ECDSA) to the list of known hosts.
Enumerating objects: 19, done.
Counting objects: 100% (19/19), done.
Compressing objects: 100% (11/11), done.
Writing objects: 100% (19/19), 1.60 KiB | 820.00 KiB/s, done.
Total 19 (delta 1), reused 0 (delta 0)
To git.acwing.com:kkoyy459/project.git
* [new branch] master -> master
Branch 'master' set up to track remote branch 'master' from 'origin'.
# acs@80826ae841a9:~/project$ git push -u # 将当前分支推送到远程仓库(第一次需要-u以后不需要)
acs@80826ae841a9:~/project$
- 将远程某个仓库下载到当前目录下
acs@80826ae841a9:~$ pwd
/home/acs
acs@80826ae841a9:~$ ls -l
total 12
drwxrwxr-x 6 acs acs 4096 Sep 18 23:42 homework
drwxrwxr-x 3 acs acs 4096 Dec 30 19:26 project
drwxrwxr-x 2 acs acs 4096 Sep 25 23:30 temp
acs@80826ae841a9:~$ rm -rf project/
acs@80826ae841a9:~$ ls -l
total 8
drwxrwxr-x 6 acs acs 4096 Sep 18 23:42 homework
drwxrwxr-x 2 acs acs 4096 Sep 25 23:30 temp
acs@80826ae841a9:~$ git clone git@git.acwing.com:kkoyy459/project.git # 将远程project仓库下载到当前目录下
Cloning into 'project'...
remote: Enumerating objects: 19, done.
remote: Counting objects: 100% (19/19), done.
remote: Compressing objects: 100% (11/11), done.
remote: Total 19 (delta 1), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (19/19), done.
Resolving deltas: 100% (1/1), done.
acs@80826ae841a9:~$ ls -l
total 12
drwxrwxr-x 6 acs acs 4096 Sep 18 23:42 homework
drwxrwxr-x 3 acs acs 4096 Dec 30 20:55 project
drwxrwxr-x 2 acs acs 4096 Sep 25 23:30 temp
acs@80826ae841a9:~$
一般默认是master分支,但是实际多人开发项目时,需要创建不同的分支
- 创建并切换到某个分支
- 查看所有分支和当前所处分支
- 切换到某个分支
- 将某个分支合并到当前分支上
- 删除某个分支
acs@80826ae841a9:~/project$ pwd
/home/acs/project
acs@80826ae841a9:~/project$ ls -l
total 8
-rw-rw-r-- 1 acs acs 4 Dec 30 20:55 main.cpp
-rw-rw-r-- 1 acs acs 16 Dec 30 20:55 readme.txt
acs@80826ae841a9:~/project$ git checkout -b dev # 创建并切换到dev这个分支
Switched to a new branch 'dev'
acs@80826ae841a9:~/project$ git branch # 查看所有分支和当前所处分支
* dev
master
acs@80826ae841a9:~/project$ vim readme.txt
acs@80826ae841a9:~/project$ cat readme.txt
111
222
333
666
777
acs@80826ae841a9:~/project$ git status
On branch dev
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: readme.txt
no changes added to commit (use "git add" and/or "git commit -a")
acs@80826ae841a9:~/project$ git add .
acs@80826ae841a9:~/project$ git commit -m "cgw add 777" # 将暂存区的内容提交到当前分支的下一个结点
[dev 6bd71bf] cgw add 777
1 file changed, 1 insertion(+)
acs@80826ae841a9:~/project$ git branch
* dev
master
acs@80826ae841a9:~/project$ git checkout master # 切换到master这个分支
Switched to branch 'master'
Your branch is up to date with 'origin/master'.
acs@80826ae841a9:~/project$ git branch
dev
* master
acs@80826ae841a9:~/project$ cat readme.txt
111
222
333
666
acs@80826ae841a9:~/project$ git merge dev # 将dev分支合并到当前分支上
Updating 8c713a9..6bd71bf
Fast-forward
readme.txt | 1 +
1 file changed, 1 insertion(+)
acs@80826ae841a9:~/project$ cat readme.txt
111
222
333
666
777
acs@80826ae841a9:~/project$ git branch -d dev # 删除dev分支
Deleted branch dev (was 6bd71bf).
acs@80826ae841a9:~/project$ git branch
* master
acs@80826ae841a9:~/project$
acs@80826ae841a9:~/project$
acs@80826ae841a9:~/project$ # ==================================================================
acs@80826ae841a9:~/project$ # 下面是展示合并分支时,发生冲突的情况
acs@80826ae841a9:~/project$ pwd
/home/acs/project
acs@80826ae841a9:~/project$ ls -l
total 8
-rw-rw-r-- 1 acs acs 4 Dec 30 20:55 main.cpp
-rw-rw-r-- 1 acs acs 20 Dec 30 21:24 readme.txt
acs@80826ae841a9:~/project$ git checkout -b dev2
Switched to a new branch 'dev2'
acs@80826ae841a9:~/project$ git branch
* dev2
master
acs@80826ae841a9:~/project$ vim readme.txt
acs@80826ae841a9:~/project$ git add .
acs@80826ae841a9:~/project$ git commit -m "cgw add 888"
[dev2 222ad45] cgw add 888
1 file changed, 1 insertion(+)
acs@80826ae841a9:~/project$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 1 commit.
(use "git push" to publish your local commits)
acs@80826ae841a9:~/project$ vim readme.txt
acs@80826ae841a9:~/project$ git add .
acs@80826ae841a9:~/project$ git commit -m "cgw add 999"
[master d5ece4c] cgw add 999
1 file changed, 1 insertion(+)
acs@80826ae841a9:~/project$ git merge dev2 # 此时,将dev2分支合并到当前分支上时会报错,因为dev2分支最新的结点和当前分支上最新的结点都是把readme.txt文件进行修改了,会被认为有冲突。因此需要手动确认readme.txt文件后,重新提交到版本库
Auto-merging readme.txt
CONFLICT (content): Merge conflict in readme.txt
Automatic merge failed; fix conflicts and then commit the result.
acs@80826ae841a9:~/project$ git status
On branch master
Your branch is ahead of 'origin/master' by 2 commits.
(use "git push" to publish your local commits)
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: readme.txt
no changes added to commit (use "git add" and/or "git commit -a")
acs@80826ae841a9:~/project$ vim readme.txt
acs@80826ae841a9:~/project$ git add .
acs@80826ae841a9:~/project$ git commit -m "cgw fix conflicts"
[master e2169ff] cgw fix conflicts
acs@80826ae841a9:~/project$ git status
On branch master
Your branch is ahead of 'origin/master' by 4 commits.
(use "git push" to publish your local commits)
nothing to commit, working tree clean
acs@80826ae841a9:~/project$ git branch -d dev2
Deleted branch dev2 (was 222ad45).
acs@80826ae841a9:~/project$ git branch
* master
acs@80826ae841a9:~/project$ git push origin master
Enumerating objects: 14, done.
Counting objects: 100% (14/14), done.
Compressing objects: 100% (8/8), done.
Writing objects: 100% (12/12), 1.03 KiB | 525.00 KiB/s, done.
Total 12 (delta 1), reused 0 (delta 0)
To git.acwing.com:kkoyy459/project.git
8c713a9..e2169ff master -> master
acs@80826ae841a9:~/project$
- 创建某个分支
- 设置本地的某个分支对应远程仓库的某个分支
- 删除远程仓库的某个分支
acs@80826ae841a9:~/project$ pwd
/home/acs/project
acs@80826ae841a9:~/project$ git branch
* master
acs@80826ae841a9:~/project$ git branch dev3 # 创建dev3分支
acs@80826ae841a9:~/project$ git checkout dev3
Switched to branch 'dev3'
acs@80826ae841a9:~/project$ vim readme.txt
acs@80826ae841a9:~/project$ git add .
acs@80826ae841a9:~/project$ git commit -m "aaa"
[dev3 442e9e5] aaa
1 file changed, 1 insertion(+)
acs@80826ae841a9:~/project$ git push --set-upstream origin dev3 # 设置本地的dev3分支对应远程仓库的dev3分支
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 293 bytes | 293.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
remote:
remote: To create a merge request for dev3, visit:
remote: https://git.acwing.com/kkoyy459/project/-/merge_requests/new?merge_request%5Bsource_branch%5D=dev3
remote:
To git.acwing.com:kkoyy459/project.git
* [new branch] dev3 -> dev3
Branch 'dev3' set up to track remote branch 'dev3' from 'origin'.
acs@80826ae841a9:~/project$ git branch
* dev3
master
acs@80826ae841a9:~/project$ git checkout master # 只有先切换到其它分支,才能把dev3分支删除掉
Switched to branch 'master'
Your branch is up to date with 'origin/master'.
acs@80826ae841a9:~/project$ git branch -d dev3 # 删除dev3分支
warning: deleting branch 'dev3' that has been merged to
'refs/remotes/origin/dev3', but not yet merged to HEAD.
Deleted branch dev3 (was 442e9e5).
acs@80826ae841a9:~/project$ git branch
* master
acs@80826ae841a9:~/project$ git push -d origin dev3 # 删除远程仓库的dev3分支
To git.acwing.com:kkoyy459/project.git
- [deleted] dev3
acs@80826ae841a9:~/project$
- 将远程的某个分支与本地的某个分支对应
- 将远程仓库的当前分支与本地仓库的当前分支合并
acs@80826ae841a9:~/project$ pwd
/home/acs/project
acs@80826ae841a9:~/project$ ls -l
total 8
-rw-rw-r-- 1 acs acs 4 Dec 30 20:55 main.cpp
-rw-rw-r-- 1 acs acs 28 Dec 31 15:37 readme.txt
acs@80826ae841a9:~/project$ git branch
* master
acs@80826ae841a9:~/project$ git checkout -b dev4
Switched to a new branch 'dev4'
acs@80826ae841a9:~/project$ vim readme.txt
acs@80826ae841a9:~/project$ git add .
acs@80826ae841a9:~/project$ git commit -m "cgw add bbb"
[dev4 d165fff] cgw add bbb
1 file changed, 1 insertion(+)
acs@80826ae841a9:~/project$ git push --set-upstream origin dev4
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 299 bytes | 299.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
remote:
remote: To create a merge request for dev4, visit:
remote: https://git.acwing.com/kkoyy459/project/-/merge_requests/new?merge_request%5Bsource_branch%5D=dev4
remote:
To git.acwing.com:kkoyy459/project.git
* [new branch] dev4 -> dev4
Branch 'dev4' set up to track remote branch 'dev4' from 'origin'.
acs@80826ae841a9:~/project$ git checkout master
Switched to branch 'master'
Your branch is up to date with 'origin/master'.
acs@80826ae841a9:~/project$ git branch -d dev4
warning: deleting branch 'dev4' that has been merged to
'refs/remotes/origin/dev4', but not yet merged to HEAD.
Deleted branch dev4 (was d165fff).
acs@80826ae841a9:~/project$ git branch
* master
acs@80826ae841a9:~/project$ git checkout -b dev4
Switched to a new branch 'dev4'
acs@80826ae841a9:~/project$ git branch --set-upstream-to=origin/dev4 dev4 # 将远程的dev4分支与本地的dev4分支对应,前提是本地需要先创建dev4分支
Branch 'dev4' set up to track remote branch 'dev4' from 'origin'.
acs@80826ae841a9:~/project$ git pull # 将远程仓库的当前分支与本地仓库的当前分支合并
Updating e2169ff..d165fff
Fast-forward
readme.txt | 1 +
1 file changed, 1 insertion(+)
# acs@80826ae841a9:~/project$ git pull origin dev4 # 将远程仓库的dev4分支与本地仓库的当前分支合并
acs@80826ae841a9:~/project$ git checkout master
Switched to branch 'master'
Your branch is up to date with 'origin/master'.
acs@80826ae841a9:~/project$ git merge dev4
Updating e2169ff..d165fff
Fast-forward
readme.txt | 1 +
1 file changed, 1 insertion(+)
acs@80826ae841a9:~/project$ git branch -d dev4
Deleted branch dev4 (was d165fff).
acs@80826ae841a9:~/project$ git push -d origin dev4
To git.acwing.com:kkoyy459/project.git
- [deleted] dev4
acs@80826ae841a9:~/project$ git push origin master
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 299 bytes | 299.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To git.acwing.com:kkoyy459/project.git
e2169ff..d165fff master -> master
acs@80826ae841a9:~/project$
-
将远程的branch_name分支拉取到本地,不会与本地仓库的当前分支合并
git checkout -t origin/branch_name
thrift
thrift官网:https://thrift.apache.org/
thrift教程:https://thrift.apache.org/tutorial/
- .thrift文件内容参考:https://raw.githubusercontent.com/apache/thrift/HEAD/tutorial/tutorial.thrift
thrift也被称为RPC(远程函数调用)框架
项目内容
本项目的主要任务是:
-
实现一个游戏节点(在AC Terminal服务器里)
- 在调用匹配节点的服务时,此节点为客户端
-
实现一个匹配节点(在AC Terminal服务器里)
- 在被游戏节点调用时,此节点为服务端
- 在调用数据存储节点的服务时,此节点为客户端
-
还有一个别人已经实现好的数据存储节点(在myserver服务器里,服务端口是9090),我们只需要去调用即可
项目演示
基础版匹配系统
已经提前完成好,但是没有演示出来的工作:
1、已经将当前目录thrift_lesson配置成git仓库
2、已经将本地仓库thrift_lesson关联到远程仓库
3、在当前目录thrift_lesson下,已经新建了三个目录(game、match_system、thrift)和一个文件(readme.md)
acs@80826ae841a9:~/thrift_lesson$ pwd
/home/acs/thrift_lesson
acs@80826ae841a9:~/thrift_lesson$ ls -l
total 16
drwxrwxr-x 2 acs acs 4096 Jan 2 23:24 game # 模拟game端服务器,相当于游戏节点
drwxrwxr-x 3 acs acs 4096 Jan 2 23:58 match_system # 模拟match_system端服务器,相当于匹配节点
-rw-rw-r-- 1 acs acs 41 Jan 2 23:11 readme.md
drwxrwxr-x 2 acs acs 4096 Jan 2 23:47 thrift # 存储所有的thrift的接口
acs@80826ae841a9:~/thrift_lesson$
acs@80826ae841a9:~/thrift_lesson$ cd thrift/
acs@80826ae841a9:~/thrift_lesson$ vim match.thrift # 新建一个match.thrift文件,看官网教程模仿
acs@80826ae841a9:~/thrift_lesson/thrift$ ls
match.thrift
acs@80826ae841a9:~/thrift_lesson/thrift$ cat match.thrift
namespace cpp match_service
struct User {
1: i32 id,
2: string name,
3: i32 score
}
service Match {
i32 add_user(1: User user, 2: string info),
i32 remove_user(1: User user, 2: string info),
}
acs@80826ae841a9:~/thrift_lesson/thrift$
acs@80826ae841a9:~/thrift_lesson/thrift$ cd ..
acs@80826ae841a9:~/thrift_lesson$ ls -l
total 16
drwxrwxr-x 2 acs acs 4096 Jan 2 23:24 game
drwxrwxr-x 3 acs acs 4096 Jan 2 23:58 match_system
-rw-rw-r-- 1 acs acs 41 Jan 2 23:11 readme.md
drwxrwxr-x 2 acs acs 4096 Jan 2 23:47 thrift
acs@80826ae841a9:~/thrift_lesson$ cd match_system/
acs@80826ae841a9:~/thrift_lesson/match_system$ mkdir src
acs@80826ae841a9:~/thrift_lesson/match_system$ ls -l
total 4
drwxrwxr-x 3 acs acs 4096 Jan 2 23:59 src
acs@80826ae841a9:~/thrift_lesson/match_system$ cd src
acs@80826ae841a9:~/thrift_lesson/match_system/src$ thrift -r --gen cpp ../../thrift/match.thrift # 通过刚刚新建的match.thrift文件,生成一个CPP版本的服务器
acs@80826ae841a9:~/thrift_lesson/match_system/src$ ls -l
total 4
drwxrwxr-x 2 acs acs 4096 May 2 20:32 gen-cpp
acs@80826ae841a9:~/thrift_lesson/match_system/src$ cd gen-cpp/
acs@80826ae841a9:~/thrift_lesson/match_system/src/gen-cpp$ ls -l
total 52
-rw-rw-r-- 1 acs acs 24115 May 2 20:32 Match.cpp
-rw-rw-r-- 1 acs acs 13108 May 2 20:32 Match.h
-rw-rw-r-- 1 acs acs 1492 May 2 20:32 Match_server.skeleton.cpp # 这个就是用CPP实现match.thrift文件中的thrift接口的一个样例,可以发现,我们定义完thrift接口后,其实不需要手动实现代码
-rw-rw-r-- 1 acs acs 3437 May 2 20:32 match_types.cpp
-rw-rw-r-- 1 acs acs 1688 May 2 20:32 match_types.h
acs@80826ae841a9:~/thrift_lesson/match_system/src/gen-cpp$ cat Match_server.skeleton.cpp
// This autogenerated skeleton file illustrates how to build a server.
// You should copy it to another filename to avoid overwriting it.
#include "Match.h"
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/server/TSimpleServer.h>
#include <thrift/transport/TServerSocket.h>
#include <thrift/transport/TBufferTransports.h>
using namespace ::apache::thrift;
using namespace ::apache::thrift::protocol;
using namespace ::apache::thrift::transport;
using namespace ::apache::thrift::server;
using namespace ::match_service;
class MatchHandler : virtual public MatchIf {
public:
MatchHandler() {
// Your initialization goes here
}
int32_t add_user(const User& user, const std::string& info) {
// Your implementation goes here
printf("add_user\n");
}
int32_t remove_user(const User& user, const std::string& info) {
// Your implementation goes here
printf("remove_user\n");
}
};
int main(int argc, char **argv) {
int port = 9090;
::std::shared_ptr<MatchHandler> handler(new MatchHandler());
::std::shared_ptr<TProcessor> processor(new MatchProcessor(handler));
::std::shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
::std::shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
::std::shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);
server.serve();
return 0;
}
acs@80826ae841a9:~/thrift_lesson/match_system/src/gen-cpp$ cd ..
acs@80826ae841a9:~/thrift_lesson/match_system/src$ ls -l
total 4
drwxrwxr-x 2 acs acs 4096 May 2 20:49 gen-cpp
acs@80826ae841a9:~/thrift_lesson/match_system/src$ mv gen-cpp/ match_server # 改下文件名
acs@80826ae841a9:~/thrift_lesson/match_system/src$ ls -l
total 4
drwxrwxr-x 2 acs acs 4096 May 2 20:49 match_server # 表示在被游戏节点调用时,此节点为服务端
acs@80826ae841a9:~/thrift_lesson/match_system/src$ mv match_server/Match_server.skeleton.cpp main.cpp
acs@80826ae841a9:~/thrift_lesson/match_system/src$ ls -l
total 8
-rw-rw-r-- 1 acs acs 1492 May 2 20:58 main.cpp # 具体的业务逻辑,仍然是需要我们手动定义的,因此我们要修改文件的内容
drwxrwxr-x 2 acs acs 4096 May 2 20:49 match_server
acs@80826ae841a9:~/thrift_lesson/match_system/src$ vim main.cpp
acs@80826ae841a9:~/thrift_lesson/match_system/src$ cat main.cpp
// This autogenerated skeleton file illustrates how to build a server.
// You should copy it to another filename to avoid overwriting it.
#include "match_server/Match.h"
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/server/TSimpleServer.h>
#include <thrift/transport/TServerSocket.h>
#include <thrift/transport/TBufferTransports.h>
using namespace ::apache::thrift;
using namespace ::apache::thrift::protocol;
using namespace ::apache::thrift::transport;
using namespace ::apache::thrift::server;
using namespace ::match_service;
class MatchHandler : virtual public MatchIf {
public:
MatchHandler() {
// Your initialization goes here
}
int32_t add_user(const User& user, const std::string& info) {
// Your implementation goes here
printf("add_user\n");
return 0;
}
int32_t remove_user(const User& user, const std::string& info) {
// Your implementation goes here
printf("remove_user\n");
return 0;
}
};
int main(int argc, char **argv) {
int port = 9090;
::std::shared_ptr<MatchHandler> handler(new MatchHandler());
::std::shared_ptr<TProcessor> processor(new MatchProcessor(handler));
::std::shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
::std::shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
::std::shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);
server.serve();
return 0;
}
acs@80826ae841a9:~/thrift_lesson/match_system/src$ g++ -c main.cpp match_server/*.cpp # 编译CPP文件
acs@80826ae841a9:~/thrift_lesson/match_system/src$ ls -l
total 800
-rw-rw-r-- 1 acs acs 318344 May 2 21:14 Match.o # 编译好的CPP文件
-rw-rw-r-- 1 acs acs 1648 May 2 21:11 main.cpp
-rw-rw-r-- 1 acs acs 443984 May 2 21:14 main.o # 编译好的CPP文件
drwxrwxr-x 2 acs acs 4096 May 2 21:09 match_server
-rw-rw-r-- 1 acs acs 42648 May 2 21:14 match_types.o # 编译好的CPP文件
acs@80826ae841a9:~/thrift_lesson/match_system/src$ g++ *.o -o main -lthrift # 把所有编译好的CPP文件链接起来,因为这里要用到thrift的动态链接库,所以要加上-lthrift
acs@80826ae841a9:~/thrift_lesson/match_system/src$ ls -l
total 1096
-rw-rw-r-- 1 acs acs 318344 May 2 21:14 Match.o
-rwxrwxr-x 1 acs acs 300352 May 2 21:22 main # 得到一个可执行文件
-rw-rw-r-- 1 acs acs 1648 May 2 21:11 main.cpp
-rw-rw-r-- 1 acs acs 443984 May 2 21:14 main.o
drwxrwxr-x 2 acs acs 4096 May 2 21:09 match_server
-rw-rw-r-- 1 acs acs 42648 May 2 21:14 match_types.o
acs@80826ae841a9:~/thrift_lesson/match_system/src$ vim main.cpp
acs@80826ae841a9:~/thrift_lesson/match_system/src$ cat main.cpp
// This autogenerated skeleton file illustrates how to build a server.
// You should copy it to another filename to avoid overwriting it.
#include "match_server/Match.h"
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/server/TSimpleServer.h>
#include <thrift/transport/TServerSocket.h>
#include <thrift/transport/TBufferTransports.h>
#include <iostream>
using namespace ::apache::thrift;
using namespace ::apache::thrift::protocol;
using namespace ::apache::thrift::transport;
using namespace ::apache::thrift::server;
using namespace ::match_service;
using namespace std;
class MatchHandler : virtual public MatchIf {
public:
MatchHandler() {
// Your initialization goes here
}
int32_t add_user(const User& user, const std::string& info) {
// Your implementation goes here
printf("add_user\n");
return 0;
}
int32_t remove_user(const User& user, const std::string& info) {
// Your implementation goes here
printf("remove_user\n");
return 0;
}
};
int main(int argc, char **argv) {
int port = 9090;
::std::shared_ptr<MatchHandler> handler(new MatchHandler());
::std::shared_ptr<TProcessor> processor(new MatchProcessor(handler));
::std::shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
::std::shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
::std::shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);
cout << "Start Match Server" << endl;
server.serve();
return 0;
}
acs@80826ae841a9:~/thrift_lesson/match_system/src$ g++ -c main.cpp # 因为我们修改了main.cpp的内容,所以需要重新编译一次main.cpp
acs@80826ae841a9:~/thrift_lesson/match_system/src$ g++ *.o -o main -lthrift # 把所有编译好的CPP文件链接起来,因为这里要用到thrift的动态链接库,所以要加上-lthrift
acs@80826ae841a9:~/thrift_lesson/match_system/src$ ls -l
total 1100
-rw-rw-r-- 1 acs acs 318344 May 2 21:14 Match.o
-rwxrwxr-x 1 acs acs 304968 May 2 21:29 main # 得到一个可执行文件
-rw-rw-r-- 1 acs acs 1734 May 2 21:27 main.cpp
-rw-rw-r-- 1 acs acs 445272 May 2 21:28 main.o
drwxrwxr-x 2 acs acs 4096 May 2 21:09 match_server
-rw-rw-r-- 1 acs acs 42648 May 2 21:14 match_types.o
acs@80826ae841a9:~/thrift_lesson/match_system/src$ ./main # 执行一下可执行文件,看看情况
Start Match Server
^C # 键盘按下CTRL + c
acs@80826ae841a9:~/thrift_lesson/match_system/src$
acs@80826ae841a9:~/thrift_lesson/match_system/src$ git status
On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed)
../
nothing added to commit but untracked files present (use "git add" to track)
acs@80826ae841a9:~/thrift_lesson/match_system/src$ git add .
acs@80826ae841a9:~/thrift_lesson/match_system/src$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: Match.o
new file: main
new file: main.cpp
new file: main.o
new file: match_server/Match.cpp
new file: match_server/Match.h
new file: match_server/match_types.cpp
new file: match_server/match_types.h
new file: match_types.o
acs@80826ae841a9:~/thrift_lesson/match_system/src$ git restore --staged *.o # 一般不会把编译好的CPP文件持久化到版本库中
acs@80826ae841a9:~/thrift_lesson/match_system/src$ git restore --staged main # 一般不会把可执行文件持久化到版本库中
acs@80826ae841a9:~/thrift_lesson/match_system/src$ # 一般只会把原文件持久化到版本库中
acs@80826ae841a9:~/thrift_lesson/match_system/src$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: main.cpp
new file: match_server/Match.cpp
new file: match_server/Match.h
new file: match_server/match_types.cpp
new file: match_server/match_types.h
Untracked files:
(use "git add <file>..." to include in what will be committed)
Match.o
main
main.o
match_types.o
acs@80826ae841a9:~/thrift_lesson/match_system/src$ git commit -m "add match server"
[master 2ae1fe4] add match server
5 files changed, 1573 insertions(+)
create mode 100644 match_system/src/main.cpp
create mode 100644 match_system/src/match_server/Match.cpp
create mode 100644 match_system/src/match_server/Match.h
create mode 100644 match_system/src/match_server/match_types.cpp
create mode 100644 match_system/src/match_server/match_types.h
acs@80826ae841a9:~/thrift_lesson/match_system/src$ git push origin master
Enumerating objects: 11, done.
Counting objects: 100% (11/11), done.
Compressing objects: 100% (9/9), done.
Writing objects: 100% (10/10), 7.40 KiB | 1.85 MiB/s, done.
Total 10 (delta 0), reused 0 (delta 0)
To git.acwing.com:kkoyy459/thrift_lesson.git
e23a048..2ae1fe4 master -> master
acs@80826ae841a9:~/thrift_lesson/match_system/src$
acs@80826ae841a9:~/thrift_lesson/match_system/src$ cd /home/acs/thrift_lesson/
acs@80826ae841a9:~/thrift_lesson$ ls -l
total 16
drwxrwxr-x 2 acs acs 4096 Jan 2 23:24 game
drwxrwxr-x 3 acs acs 4096 Jan 2 23:58 match_system
-rw-rw-r-- 1 acs acs 41 Jan 2 23:11 readme.md
drwxrwxr-x 2 acs acs 4096 Jan 2 23:47 thrift
acs@80826ae841a9:~/thrift_lesson$ cd game/
acs@80826ae841a9:~/thrift_lesson/game$ mkdir src
acs@80826ae841a9:~/thrift_lesson/game$ ls -l
total 4
drwxrwxr-x 2 acs acs 4096 May 3 10:24 src
acs@80826ae841a9:~/thrift_lesson/game$ cd src
acs@80826ae841a9:~/thrift_lesson/game/src$ thrift -r --gen py ../../thrift/match.thrift # 通过刚刚新建的match.thrift文件,生成一个Python版本的服务器
acs@80826ae841a9:~/thrift_lesson/game/src$ ls -l
total 4
drwxrwxr-x 3 acs acs 4096 May 3 10:30 gen-py
acs@80826ae841a9:~/thrift_lesson/game/src$ mv gen-py/ match_client # 改下文件名
acs@80826ae841a9:~/thrift_lesson/game/src$ ls -l
total 4
drwxrwxr-x 3 acs acs 4096 May 3 10:30 match_client # 表示在调用匹配节点的服务时,此节点为客户端
acs@80826ae841a9:~/thrift_lesson/game/src$ cd match_client/
acs@80826ae841a9:~/thrift_lesson/game/src/match_client$ ls -l
total 4
-rw-rw-r-- 1 acs acs 0 May 3 10:30 __init__.py
drwxrwxr-x 2 acs acs 4096 May 3 10:30 match
acs@80826ae841a9:~/thrift_lesson/game/src/match_client$ cd match/
acs@80826ae841a9:~/thrift_lesson/game/src/match_client/match$ ls -l
total 32
-rwxr-xr-x 1 acs acs 2992 May 3 10:30 Match-remote # 这个文件是用Python实现服务端的一个样例,在这里我们用不到,可以删掉,因为我们需要的是客户端
-rw-rw-r-- 1 acs acs 14947 May 3 10:30 Match.py
-rw-rw-r-- 1 acs acs 43 May 3 10:30 __init__.py
-rw-rw-r-- 1 acs acs 366 May 3 10:30 constants.py
-rw-rw-r-- 1 acs acs 3291 May 3 10:30 ttypes.py
acs@80826ae841a9:~/thrift_lesson/game/src/match_client/match$ rm Match-remote
acs@80826ae841a9:~/thrift_lesson/game/src/match_client/match$ ls -l
total 28
-rw-rw-r-- 1 acs acs 14947 May 3 10:30 Match.py
-rw-rw-r-- 1 acs acs 43 May 3 10:30 __init__.py
-rw-rw-r-- 1 acs acs 366 May 3 10:30 constants.py
-rw-rw-r-- 1 acs acs 3291 May 3 10:30 ttypes.py
acs@80826ae841a9:~/thrift_lesson/game/src/match_client/match$ cd ../../
acs@80826ae841a9:~/thrift_lesson/game/src$ ls -l
total 4
drwxrwxr-x 3 acs acs 4096 May 3 10:30 match_client
acs@80826ae841a9:~/thrift_lesson/game/src$ vim client.py # 基于官网给出的用Python实现客户端的样例代码,自己修改实现代码
acs@80826ae841a9:~/thrift_lesson/game/src$ cat client.py
from match_client.match import Match
from match_client.match.ttypes import User
from thrift import Thrift
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
def main():
# Make socket
transport = TSocket.TSocket('localhost', 9090)
# Buffering is critical. Raw sockets are very slow
transport = TTransport.TBufferedTransport(transport)
# Wrap in a protocol
protocol = TBinaryProtocol.TBinaryProtocol(transport)
# Create a client to use the protocol encoder
client = Match.Client(protocol)
# Connect!
transport.open()
user = User(1, 'yxc', 1500)
client.add_user(user, "")
# Close!
transport.close()
if __name__ == "__main__":
main()
acs@80826ae841a9:~/thrift_lesson/game/src$ ls -l
total 8
-rw-rw-r-- 1 acs acs 770 May 3 11:14 client.py
drwxrwxr-x 3 acs acs 4096 May 3 10:30 match_client
acs@80826ae841a9:~/thrift_lesson/game/src$
-
下面打开了两个Terminal
-
第一个Terminal
acs@80826ae841a9:~/thrift_lesson/game/src$ pwd /home/acs/thrift_lesson/game/src acs@80826ae841a9:~/thrift_lesson/game/src$ cd ../../match_system/src/ acs@80826ae841a9:~/thrift_lesson/match_system/src$ ls -l total 1100 -rw-rw-r-- 1 acs acs 318344 May 2 21:14 Match.o -rwxrwxr-x 1 acs acs 304968 May 2 21:29 main -rw-rw-r-- 1 acs acs 1734 May 2 21:27 main.cpp -rw-rw-r-- 1 acs acs 445272 May 2 21:28 main.o drwxrwxr-x 2 acs acs 4096 May 2 21:09 match_server -rw-rw-r-- 1 acs acs 42648 May 2 21:14 match_types.o acs@80826ae841a9:~/thrift_lesson/match_system/src$ ./main # 先把匹配节点的服务端启动 Start Match Server add_user # 每启动一次游戏节点的客户端,则会弹出一行这个东西,说明游戏节点的客户端成功调用了匹配节点的服务端 add_user add_user ^C acs@80826ae841a9:~/thrift_lesson/match_system/src$
-
第二个Terminal
acs@80826ae841a9:~/thrift_lesson/game/src$ pwd /home/acs/thrift_lesson/game/src acs@80826ae841a9:~/thrift_lesson/game/src$ ls -l total 8 -rw-rw-r-- 1 acs acs 770 May 3 11:14 client.py drwxrwxr-x 3 acs acs 4096 May 3 10:30 match_client acs@80826ae841a9:~/thrift_lesson/game/src$ python3 client.py # 启动一次游戏节点的客户端 acs@80826ae841a9:~/thrift_lesson/game/src$ python3 client.py # 启动一次游戏节点的客户端 acs@80826ae841a9:~/thrift_lesson/game/src$ python3 client.py # 启动一次游戏节点的客户端 acs@80826ae841a9:~/thrift_lesson/game/src$
-
acs@80826ae841a9:~/thrift_lesson/game/src$ pwd
/home/acs/thrift_lesson/game/src
acs@80826ae841a9:~/thrift_lesson/game/src$ ls -l
total 8
-rw-rw-r-- 1 acs acs 770 May 3 11:14 client.py
drwxrwxr-x 4 acs acs 4096 May 3 16:32 match_client
acs@80826ae841a9:~/thrift_lesson/game/src$ git status
On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed)
../
../../match_system/src/Match.o
../../match_system/src/main
../../match_system/src/main.o
../../match_system/src/match_types.o
nothing added to commit but untracked files present (use "git add" to track)
acs@80826ae841a9:~/thrift_lesson/game/src$ git add .
acs@80826ae841a9:~/thrift_lesson/game/src$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: client.py
new file: match_client/__init__.py
new file: match_client/__pycache__/__init__.cpython-38.pyc
new file: match_client/match/Match.py
new file: match_client/match/__init__.py
new file: match_client/match/__pycache__/Match.cpython-38.pyc
new file: match_client/match/__pycache__/__init__.cpython-38.pyc
new file: match_client/match/__pycache__/ttypes.cpython-38.pyc
new file: match_client/match/constants.py
new file: match_client/match/ttypes.py
Untracked files:
(use "git add <file>..." to include in what will be committed)
../../match_system/src/Match.o
../../match_system/src/main
../../match_system/src/main.o
../../match_system/src/match_types.o
acs@80826ae841a9:~/thrift_lesson/game/src$ git restore --staged *.pyc # 一般不会把.pyc后缀的文件持久化到版本库中,因为这些文件都是中间过程的文件
acs@80826ae841a9:~/thrift_lesson/game/src$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: client.py
new file: match_client/__init__.py
new file: match_client/match/Match.py
new file: match_client/match/__init__.py
new file: match_client/match/constants.py
new file: match_client/match/ttypes.py
Untracked files:
(use "git add <file>..." to include in what will be committed)
match_client/__pycache__/
match_client/match/__pycache__/
../../match_system/src/Match.o
../../match_system/src/main
../../match_system/src/main.o
../../match_system/src/match_types.o
acs@80826ae841a9:~/thrift_lesson/game/src$ git commit -m "add match client"
[master 2bf6f1c] add match client
6 files changed, 617 insertions(+)
create mode 100644 game/src/client.py
create mode 100644 game/src/match_client/__init__.py
create mode 100644 game/src/match_client/match/Match.py
create mode 100644 game/src/match_client/match/__init__.py
create mode 100644 game/src/match_client/match/constants.py
create mode 100644 game/src/match_client/match/ttypes.py
acs@80826ae841a9:~/thrift_lesson/game/src$ git push origin master
Enumerating objects: 13, done.
Counting objects: 100% (13/13), done.
Compressing objects: 100% (9/9), done.
Writing objects: 100% (12/12), 4.27 KiB | 1.42 MiB/s, done.
Total 12 (delta 0), reused 0 (delta 0)
To git.acwing.com:kkoyy459/thrift_lesson.git
2ae1fe4..2bf6f1c master -> master
acs@80826ae841a9:~/thrift_lesson/game/src$
acs@80826ae841a9:~/thrift_lesson/game/src$ ls -l
total 8
-rw-rw-r-- 1 acs acs 770 May 3 11:14 client.py
drwxrwxr-x 4 acs acs 4096 May 3 16:32 match_client
acs@80826ae841a9:~/thrift_lesson/game/src$ vim client.py # 修改代码
acs@80826ae841a9:~/thrift_lesson/game/src$ cat client.py
from match_client.match import Match
from match_client.match.ttypes import User
from thrift import Thrift
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
from sys import stdin
def operate(op, user_id, username, score):
# Make socket
transport = TSocket.TSocket('localhost', 9090)
# Buffering is critical. Raw sockets are very slow
transport = TTransport.TBufferedTransport(transport)
# Wrap in a protocol
protocol = TBinaryProtocol.TBinaryProtocol(transport)
# Create a client to use the protocol encoder
client = Match.Client(protocol)
# Connect!
transport.open()
user = User(user_id, username, score)
if op == "add":
client.add_user(user, "")
elif op == "remove":
client.remove_user(user, "")
# Close!
transport.close()
def main():
for line in stdin:
op, user_id, username, score = line.split(' ')
operate(op, int(user_id), username, int(score))
if __name__ == "__main__":
main()
acs@80826ae841a9:~/thrift_lesson/game/src$
下面打开了两个Terminal
-
第一个Terminal
acs@80826ae841a9:~/thrift_lesson/game/src$ pwd /home/acs/thrift_lesson/game/src acs@80826ae841a9:~/thrift_lesson/game/src$ cd ../../match_system/src/ acs@80826ae841a9:~/thrift_lesson/match_system/src$ ls -l total 1100 -rw-rw-r-- 1 acs acs 318344 May 2 21:14 Match.o -rwxrwxr-x 1 acs acs 304968 May 2 21:29 main -rw-rw-r-- 1 acs acs 1734 May 2 21:27 main.cpp -rw-rw-r-- 1 acs acs 445272 May 2 21:28 main.o drwxrwxr-x 2 acs acs 4096 May 2 21:09 match_server -rw-rw-r-- 1 acs acs 42648 May 2 21:14 match_types.o acs@80826ae841a9:~/thrift_lesson/match_system/src$ ./main # 先把匹配节点的服务端启动 Start Match Server add_user remove_user add_user add_user remove_user
-
第二个Terminal
acs@80826ae841a9:~/thrift_lesson/game/src$ pwd /home/acs/thrift_lesson/game/src acs@80826ae841a9:~/thrift_lesson/game/src$ ls -l total 8 -rw-rw-r-- 1 acs acs 1070 May 3 17:27 client.py drwxrwxr-x 4 acs acs 4096 May 3 16:32 match_client acs@80826ae841a9:~/thrift_lesson/game/src$ python3 client.py # 启动一次游戏节点的客户端,从终端读入参数,然后观察匹配节点的服务端有什么反应 add 1 yxc 1500 remove 1 yxc 1500 add 2 cgw 1000 add 3 xxx 999 remove 4 fff 888
acs@80826ae841a9:~/thrift_lesson/game/src$ pwd
/home/acs/thrift_lesson/game/src
acs@80826ae841a9:~/thrift_lesson/game/src$ ls -l
total 8
-rw-rw-r-- 1 acs acs 1070 May 3 17:27 client.py
drwxrwxr-x 4 acs acs 4096 May 3 16:32 match_client
acs@80826ae841a9:~/thrift_lesson/game/src$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: client.py
Untracked files:
(use "git add <file>..." to include in what will be committed)
match_client/__pycache__/
match_client/match/__pycache__/
../../match_system/src/Match.o
../../match_system/src/main
../../match_system/src/main.o
../../match_system/src/match_types.o
no changes added to commit (use "git add" and/or "git commit -a")
acs@80826ae841a9:~/thrift_lesson/game/src$ git add .
acs@80826ae841a9:~/thrift_lesson/game/src$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: client.py
new file: match_client/__pycache__/__init__.cpython-38.pyc
new file: match_client/match/__pycache__/Match.cpython-38.pyc
new file: match_client/match/__pycache__/__init__.cpython-38.pyc
new file: match_client/match/__pycache__/ttypes.cpython-38.pyc
Untracked files:
(use "git add <file>..." to include in what will be committed)
../../match_system/src/Match.o
../../match_system/src/main
../../match_system/src/main.o
../../match_system/src/match_types.o
acs@80826ae841a9:~/thrift_lesson/game/src$ git restore --staged *.pyc # 一般不会把.pyc后缀的文件持久化到版本库中,因为这些文件都是中间过程的文件
acs@80826ae841a9:~/thrift_lesson/game/src$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: client.py
Untracked files:
(use "git add <file>..." to include in what will be committed)
match_client/__pycache__/
match_client/match/__pycache__/
../../match_system/src/Match.o
../../match_system/src/main
../../match_system/src/main.o
../../match_system/src/match_types.o
acs@80826ae841a9:~/thrift_lesson/game/src$ git commit -m "finish match-client"
[master b9f6107] finish match-client
1 file changed, 16 insertions(+), 3 deletions(-)
acs@80826ae841a9:~/thrift_lesson/game/src$ git push origin master
Enumerating objects: 9, done.
Counting objects: 100% (9/9), done.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (5/5), 676 bytes | 676.00 KiB/s, done.
Total 5 (delta 1), reused 0 (delta 0)
To git.acwing.com:kkoyy459/thrift_lesson.git
2bf6f1c..b9f6107 master -> master
acs@80826ae841a9:~/thrift_lesson/game/src$
acs@80826ae841a9:~/thrift_lesson/game/src$ cd ../../match_system/src/
acs@80826ae841a9:~/thrift_lesson/match_system/src$ ls -l
total 1100
-rw-rw-r-- 1 acs acs 318344 May 2 21:14 Match.o
-rwxrwxr-x 1 acs acs 304968 May 2 21:29 main
-rw-rw-r-- 1 acs acs 1734 May 2 21:27 main.cpp
-rw-rw-r-- 1 acs acs 445272 May 2 21:28 main.o
drwxrwxr-x 2 acs acs 4096 May 2 21:09 match_server
-rw-rw-r-- 1 acs acs 42648 May 2 21:14 match_types.o
acs@80826ae841a9:~/thrift_lesson/match_system/src$ vim main.cpp
acs@80826ae841a9:~/thrift_lesson/match_system/src$ cat main.cpp
// This autogenerated skeleton file illustrates how to build a server.
// You should copy it to another filename to avoid overwriting it.
#include "match_server/Match.h"
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/server/TSimpleServer.h>
#include <thrift/transport/TServerSocket.h>
#include <thrift/transport/TBufferTransports.h>
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <vector>
using namespace ::apache::thrift;
using namespace ::apache::thrift::protocol;
using namespace ::apache::thrift::transport;
using namespace ::apache::thrift::server;
using namespace ::match_service;
using namespace std;
struct Task
{
User user;
string type;
};
struct MessageQueue
{
queue<Task> q;
mutex m;
condition_variable cv;
}message_queue;
class Pool
{
public:
void save_result(int a, int b)
{
printf("Match Result: %d %d\n", a, b);
}
void match()
{
while (users.size() > 1)
{
auto a = users[0], b = users[1];
users.erase(users.begin());
users.erase(users.begin());
save_result(a.id, b.id);
}
}
void add(User user)
{
users.push_back(user);
}
void remove(User user)
{
for (uint32_t i = 0; i < users.size(); i++)
if (users[i].id == user.id)
{
users.erase(users.begin() + i);
break;
}
}
private:
vector<User> users;
}pool;
class MatchHandler : virtual public MatchIf {
public:
MatchHandler() {
// Your initialization goes here
}
int32_t add_user(const User& user, const std::string& info) {
// Your implementation goes here
printf("add_user\n");
unique_lock<mutex> lck(message_queue.m);
message_queue.q.push({user, "add"});
message_queue.cv.notify_all();
return 0;
}
int32_t remove_user(const User& user, const std::string& info) {
// Your implementation goes here
printf("remove_user\n");
unique_lock<mutex> lck(message_queue.m);
message_queue.q.push({user, "remove"});
message_queue.cv.notify_all();
return 0;
}
};
void consume_task()
{
while (true)
{
unique_lock<mutex> lck(message_queue.m);
if (message_queue.q.empty())
{
message_queue.cv.wait(lck);
}
else
{
auto task = message_queue.q.front();
message_queue.q.pop();
lck.unlock();
if (task.type == "add") pool.add(task.user);
else if (task.type == "remove") pool.remove(task.user);
pool.match();
}
}
}
int main(int argc, char **argv) {
int port = 9090;
::std::shared_ptr<MatchHandler> handler(new MatchHandler());
::std::shared_ptr<TProcessor> processor(new MatchProcessor(handler));
::std::shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
::std::shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
::std::shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);
cout << "Start Match Server" << endl;
thread matching_thread(consume_task);
server.serve();
return 0;
}
acs@80826ae841a9:~/thrift_lesson/match_system/src$ g++ -c main.cpp # 因为我们修改了main.cpp的内容,所以需要重新编译一次main.cpp
acs@80826ae841a9:~/thrift_lesson/match_system/src$ g++ *.o -o main -lthrift -pthread # 把所有编译好的CPP文件链接起来,因为这里要用到thrift和thread的动态链接库,所以要加上-lthrift、-pthread
acs@80826ae841a9:~/thrift_lesson/match_system/src$
下面打开了两个Terminal
-
第一个Terminal
acs@80826ae841a9:~/thrift_lesson/match_system/src$ pwd /home/acs/thrift_lesson/match_system/src acs@80826ae841a9:~/thrift_lesson/match_system/src$ ls -l total 1292 -rw-rw-r-- 1 acs acs 318344 May 2 21:14 Match.o -rwxrwxr-x 1 acs acs 354832 May 4 17:24 main -rw-rw-r-- 1 acs acs 3642 May 4 17:10 main.cpp -rw-rw-r-- 1 acs acs 592984 May 4 17:17 main.o drwxrwxr-x 2 acs acs 4096 May 2 21:09 match_server -rw-rw-r-- 1 acs acs 42648 May 2 21:14 match_types.o acs@80826ae841a9:~/thrift_lesson/match_system/src$ ./main # 先把匹配节点的服务端启动 Start Match Server add_user add_user Match Result: 1 2 add_user remove_user add_user add_user Match Result: 4 5
-
第二个Terminal
acs@80826ae841a9:~/thrift_lesson/match_system/src$ cd ../../game/src/ acs@80826ae841a9:~/thrift_lesson/game/src$ ls -l total 8 -rw-rw-r-- 1 acs acs 1070 May 3 17:27 client.py drwxrwxr-x 4 acs acs 4096 May 3 16:32 match_client acs@80826ae841a9:~/thrift_lesson/game/src$ python3 client.py # 启动一次游戏节点的客户端,从终端读入参数,然后观察匹配节点的服务端有什么反应 add 1 1 1000 add 2 2 1000 add 3 3 1000 remove 3 3 1000 add 4 4 1000 add 5 5 1000
acs@80826ae841a9:~/thrift_lesson/match_system/src$ pwd
/home/acs/thrift_lesson/match_system/src
acs@80826ae841a9:~/thrift_lesson/match_system/src$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: main.cpp
Untracked files:
(use "git add <file>..." to include in what will be committed)
../../game/src/match_client/__pycache__/
../../game/src/match_client/match/__pycache__/
Match.o
main
main.o
match_types.o
no changes added to commit (use "git add" and/or "git commit -a")
acs@80826ae841a9:~/thrift_lesson/match_system/src$ git add main.cpp
acs@80826ae841a9:~/thrift_lesson/match_system/src$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: main.cpp
Untracked files:
(use "git add <file>..." to include in what will be committed)
../../game/src/match_client/__pycache__/
../../game/src/match_client/match/__pycache__/
Match.o
main
main.o
match_types.o
acs@80826ae841a9:~/thrift_lesson/match_system/src$ git commit -m "match-server version:2.0"
[master 269c41b] match-server version:2.0
1 file changed, 94 insertions(+)
acs@80826ae841a9:~/thrift_lesson/match_system/src$ git push origin master
Enumerating objects: 9, done.
Counting objects: 100% (9/9), done.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (5/5), 1.58 KiB | 807.00 KiB/s, done.
Total 5 (delta 0), reused 0 (delta 0)
To git.acwing.com:kkoyy459/thrift_lesson.git
b9f6107..269c41b master -> master
acs@80826ae841a9:~/thrift_lesson/match_system/src$
acs@80826ae841a9:~/thrift_lesson/match_system/src$ cd ../../thrift/
acs@80826ae841a9:~/thrift_lesson/thrift$ ls -l
total 4
-rw-rw-r-- 1 acs acs 216 Jan 2 23:47 match.thrift
acs@80826ae841a9:~/thrift_lesson/thrift$ vim save.thrift # 新建一个save.thrift文件,内容为数据存储节点提供给匹配节点进行调用的接口,这个接口别人已经实现好,直接copy别人的内容就行
acs@80826ae841a9:~/thrift_lesson/thrift$ cat save.thrift
namespace cpp save_service
service Save {
/**
* username: myserver的名称
* password: myserver的密码的md5sum的前8位
* 用户名密码验证成功会返回0,验证失败会返回1
* 验证成功后,结果会被保存到myserver:homework/lesson_6/result.txt中
*/
i32 save_data(1: string username, 2: string password, 3: i32 player1_id, 4: i32 player2_id)
}
acs@80826ae841a9:~/thrift_lesson/thrift$ ls -l
total 8
-rw-rw-r-- 1 acs acs 216 Jan 2 23:47 match.thrift
-rw-rw-r-- 1 acs acs 404 May 5 18:34 save.thrift
acs@80826ae841a9:~/thrift_lesson/thrift$ homework 4 getinfo # 获取myserver的名称和密码
User: acs_11511 # myserver的名称
HostName: 123.57.67.128
Password: ******** # myserver的密码(此处密码已经手动屏蔽)
acs@80826ae841a9:~/thrift_lesson/thrift$ md5sum # 可以把指定的字符串转变成md5sum
******** # 输入myserver的密码,然后键盘按下回车,然后键盘按下CTRL + d
92da7fd2b3421476ef7c0b20e69ddfe0 - # 可以获得myserver的密码的md5sum
acs@80826ae841a9:~/thrift_lesson/thrift$
acs@80826ae841a9:~/thrift_lesson/thrift$ cd ../match_system/src/
acs@80826ae841a9:~/thrift_lesson/match_system/src$ ls -l
total 1292
-rw-rw-r-- 1 acs acs 318344 May 2 21:14 Match.o
-rwxrwxr-x 1 acs acs 354832 May 4 17:24 main
-rw-rw-r-- 1 acs acs 3642 May 4 17:10 main.cpp
-rw-rw-r-- 1 acs acs 592984 May 4 17:17 main.o
drwxrwxr-x 2 acs acs 4096 May 2 21:09 match_server
-rw-rw-r-- 1 acs acs 42648 May 2 21:14 match_types.o
acs@80826ae841a9:~/thrift_lesson/match_system/src$ thrift -r --gen cpp ../../thrift/save.thrift # 通过刚刚新建的save.thrift文件,生成一个CPP版本的服务器
acs@80826ae841a9:~/thrift_lesson/match_system/src$ ls -l
total 1296
-rw-rw-r-- 1 acs acs 318344 May 2 21:14 Match.o
drwxrwxr-x 2 acs acs 4096 May 5 19:00 gen-cpp
-rwxrwxr-x 1 acs acs 354832 May 4 17:24 main
-rw-rw-r-- 1 acs acs 3642 May 4 17:10 main.cpp
-rw-rw-r-- 1 acs acs 592984 May 4 17:17 main.o
drwxrwxr-x 2 acs acs 4096 May 2 21:09 match_server
-rw-rw-r-- 1 acs acs 42648 May 2 21:14 match_types.o
acs@80826ae841a9:~/thrift_lesson/match_system/src$ mv gen-cpp/ save_client # 改下文件名
acs@80826ae841a9:~/thrift_lesson/match_system/src$ ls -l
total 1296
-rw-rw-r-- 1 acs acs 318344 May 2 21:14 Match.o
-rwxrwxr-x 1 acs acs 354832 May 4 17:24 main
-rw-rw-r-- 1 acs acs 3642 May 4 17:10 main.cpp
-rw-rw-r-- 1 acs acs 592984 May 4 17:17 main.o
drwxrwxr-x 2 acs acs 4096 May 2 21:09 match_server
-rw-rw-r-- 1 acs acs 42648 May 2 21:14 match_types.o
drwxrwxr-x 2 acs acs 4096 May 5 19:00 save_client # 表示在调用数据存储节点的服务时,此节点为客户端
acs@80826ae841a9:~/thrift_lesson/match_system/src$ cd save_client/
acs@80826ae841a9:~/thrift_lesson/match_system/src/save_client$ ls -l
total 36
-rw-rw-r-- 1 acs acs 14502 May 5 19:00 Save.cpp
-rw-rw-r-- 1 acs acs 11764 May 5 19:00 Save.h
-rw-rw-r-- 1 acs acs 1759 May 5 19:00 Save_server.skeleton.cpp # 这个文件是用CPP实现服务端的一个样例,在这里我们用不到,可以删掉,因为我们需要的是客户端
-rw-rw-r-- 1 acs acs 468 May 5 19:00 save_types.h
acs@80826ae841a9:~/thrift_lesson/match_system/src/save_client$ rm Save_server.skeleton.cpp
acs@80826ae841a9:~/thrift_lesson/match_system/src/save_client$ ls -l
total 32
-rw-rw-r-- 1 acs acs 14502 May 5 19:00 Save.cpp
-rw-rw-r-- 1 acs acs 11764 May 5 19:00 Save.h
-rw-rw-r-- 1 acs acs 468 May 5 19:00 save_types.h
acs@80826ae841a9:~/thrift_lesson/match_system/src/save_client$
acs@80826ae841a9:~/thrift_lesson/match_system/src/save_client$ cd ..
acs@80826ae841a9:~/thrift_lesson/match_system/src$ ls -l
total 1296
-rw-rw-r-- 1 acs acs 318344 May 2 21:14 Match.o
-rwxrwxr-x 1 acs acs 354832 May 4 17:24 main
-rw-rw-r-- 1 acs acs 3642 May 4 17:10 main.cpp
-rw-rw-r-- 1 acs acs 592984 May 4 17:17 main.o
drwxrwxr-x 2 acs acs 4096 May 2 21:09 match_server
-rw-rw-r-- 1 acs acs 42648 May 2 21:14 match_types.o
drwxrwxr-x 2 acs acs 4096 May 5 19:04 save_client
acs@80826ae841a9:~/thrift_lesson/match_system/src$ vim main.cpp
acs@80826ae841a9:~/thrift_lesson/match_system/src$ cat main.cpp
// This autogenerated skeleton file illustrates how to build a server.
// You should copy it to another filename to avoid overwriting it.
#include "match_server/Match.h"
#include "save_client/Save.h"
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/server/TSimpleServer.h>
#include <thrift/transport/TServerSocket.h>
#include <thrift/transport/TBufferTransports.h>
#include <thrift/transport/TTransportUtils.h>
#include <thrift/transport/TSocket.h>
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <vector>
using namespace ::apache::thrift;
using namespace ::apache::thrift::protocol;
using namespace ::apache::thrift::transport;
using namespace ::apache::thrift::server;
using namespace ::match_service;
using namespace ::save_service;
using namespace std;
struct Task
{
User user;
string type;
};
struct MessageQueue
{
queue<Task> q;
mutex m;
condition_variable cv;
}message_queue;
class Pool
{
public:
void save_result(int a, int b)
{
printf("Match Result: %d %d\n", a, b);
std::shared_ptr<TTransport> socket(new TSocket("123.57.67.128", 9090));
std::shared_ptr<TTransport> transport(new TBufferedTransport(socket));
std::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
SaveClient client(protocol);
try {
transport->open();
int res = client.save_data("acs_11511", "92da7fd2", a, b);
if (!res) puts("success");
else puts("failed");
transport->close();
} catch (TException& tx) {
cout << "ERROR: " << tx.what() << endl;
}
}
void match()
{
while (users.size() > 1)
{
auto a = users[0], b = users[1];
users.erase(users.begin());
users.erase(users.begin());
save_result(a.id, b.id);
}
}
void add(User user)
{
users.push_back(user);
}
void remove(User user)
{
for (uint32_t i = 0; i < users.size(); i++)
if (users[i].id == user.id)
{
users.erase(users.begin() + i);
break;
}
}
private:
vector<User> users;
}pool;
class MatchHandler : virtual public MatchIf {
public:
MatchHandler() {
// Your initialization goes here
}
int32_t add_user(const User& user, const std::string& info) {
// Your implementation goes here
printf("add_user\n");
unique_lock<mutex> lck(message_queue.m);
message_queue.q.push({user, "add"});
message_queue.cv.notify_all();
return 0;
}
int32_t remove_user(const User& user, const std::string& info) {
// Your implementation goes here
printf("remove_user\n");
unique_lock<mutex> lck(message_queue.m);
message_queue.q.push({user, "remove"});
message_queue.cv.notify_all();
return 0;
}
};
void consume_task()
{
while (true)
{
unique_lock<mutex> lck(message_queue.m);
if (message_queue.q.empty())
{
message_queue.cv.wait(lck);
}
else
{
auto task = message_queue.q.front();
message_queue.q.pop();
lck.unlock();
if (task.type == "add") pool.add(task.user);
else if (task.type == "remove") pool.remove(task.user);
pool.match();
}
}
}
int main(int argc, char **argv) {
int port = 9090;
::std::shared_ptr<MatchHandler> handler(new MatchHandler());
::std::shared_ptr<TProcessor> processor(new MatchProcessor(handler));
::std::shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
::std::shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
::std::shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);
cout << "Start Match Server" << endl;
thread matching_thread(consume_task);
server.serve();
return 0;
}
acs@80826ae841a9:~/thrift_lesson/match_system/src$ g++ -c main.cpp # 因为我们修改了main.cpp的内容,所以需要重新编译一次main.cpp
acs@80826ae841a9:~/thrift_lesson/match_system/src$ g++ -c save_client/*.cpp # 编译CPP文件
acs@80826ae841a9:~/thrift_lesson/match_system/src$ g++ *.o -o main -lthrift -pthread # 把所有编译好的CPP文件链接起来,因为这里要用到thrift和thread的动态链接库,所以要加上-lthrift、-pthread
acs@80826ae841a9:~/thrift_lesson/match_system/src$ ls -l
total 1708
-rw-rw-r-- 1 acs acs 318344 May 2 21:14 Match.o
-rw-rw-r-- 1 acs acs 282384 May 5 20:00 Save.o
-rwxrwxr-x 1 acs acs 447504 May 5 20:00 main
-rw-rw-r-- 1 acs acs 4435 May 5 19:57 main.cpp
-rw-rw-r-- 1 acs acs 633184 May 5 19:59 main.o
drwxrwxr-x 2 acs acs 4096 May 2 21:09 match_server
-rw-rw-r-- 1 acs acs 42648 May 2 21:14 match_types.o
drwxrwxr-x 2 acs acs 4096 May 5 19:04 save_client
acs@80826ae841a9:~/thrift_lesson/match_system/src$
下面打开了三个Terminal
-
第一个Terminal
acs@80826ae841a9:~/thrift_lesson/match_system/src$ pwd /home/acs/thrift_lesson/match_system/src acs@80826ae841a9:~/thrift_lesson/match_system/src$ ls -l total 1708 -rw-rw-r-- 1 acs acs 318344 May 2 21:14 Match.o -rw-rw-r-- 1 acs acs 282384 May 5 20:00 Save.o -rwxrwxr-x 1 acs acs 447504 May 5 20:00 main -rw-rw-r-- 1 acs acs 4435 May 5 19:57 main.cpp -rw-rw-r-- 1 acs acs 633184 May 5 19:59 main.o drwxrwxr-x 2 acs acs 4096 May 2 21:09 match_server -rw-rw-r-- 1 acs acs 42648 May 2 21:14 match_types.o drwxrwxr-x 2 acs acs 4096 May 5 19:04 save_client acs@80826ae841a9:~/thrift_lesson/match_system/src$ ./main # 先把匹配节点的服务端启动 Start Match Server add_user add_user Match Result: 3 4 success add_user add_user Match Result: 5 100 success
-
第二个Terminal
acs@80826ae841a9:~/thrift_lesson/match_system/src$ cd ../../game/src/ acs@80826ae841a9:~/thrift_lesson/game/src$ ls -l total 8 -rw-rw-r-- 1 acs acs 1070 May 3 17:27 client.py drwxrwxr-x 4 acs acs 4096 May 3 16:32 match_client acs@80826ae841a9:~/thrift_lesson/game/src$ python3 client.py # 启动一次游戏节点的客户端,从终端读入参数,然后观察匹配节点的服务端有什么反应 add 3 3 1000 add 4 4 1000 add 5 5 1000 add 100 100 1000
-
第三个Terminal
acs@80826ae841a9:~/thrift_lesson/match_system/src$ ssh myserver Welcome to AC Server * Tutorial: https://www.acwing.com/activity/content/57/ __ __________ __ ______ ___ _______ / \ / ______/ / \ \| || \ | |/ _____| / /\ \ | | | | /\ | || || \ \| || / ___ / /__\ \| | | | / \ | || || |\ \ || | |_ | / ______ \ \_____\ \/ /\ \/ /| || | \ || \____| | /_/ \_\_______\__/ \__/ |_||_| \_|\________/ acs_11511@acs:~$ cd homework/lesson_6/ acs_11511@acs:~/homework/lesson_6$ ls -l total 4 -rw-r--r-- 1 acs_11511 acs_11511 21 May 5 20:12 result.txt acs_11511@acs:~/homework/lesson_6$ cat result.txt # 查看数据存储节点是否成功把数据存储下来 result: 3 4 177d5bf3 acs_11511@acs:~/homework/lesson_6$ cat result.txt result: 5 100 1a639ac5 acs_11511@acs:~/homework/lesson_6$
acs@80826ae841a9:~/thrift_lesson/match_system/src$ pwd
/home/acs/thrift_lesson/match_system/src
acs@80826ae841a9:~/thrift_lesson/match_system/src$ ls -l
total 1708
-rw-rw-r-- 1 acs acs 318344 May 2 21:14 Match.o
-rw-rw-r-- 1 acs acs 282384 May 5 20:00 Save.o
-rwxrwxr-x 1 acs acs 447504 May 5 20:00 main
-rw-rw-r-- 1 acs acs 4435 May 5 19:57 main.cpp
-rw-rw-r-- 1 acs acs 633184 May 5 19:59 main.o
drwxrwxr-x 2 acs acs 4096 May 2 21:09 match_server
-rw-rw-r-- 1 acs acs 42648 May 2 21:14 match_types.o
drwxrwxr-x 2 acs acs 4096 May 5 19:04 save_client
acs@80826ae841a9:~/thrift_lesson/match_system/src$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: main.cpp
Untracked files:
(use "git add <file>..." to include in what will be committed)
../../game/src/match_client/__pycache__/
../../game/src/match_client/match/__pycache__/
Match.o
Save.o
main
main.o
match_types.o
save_client/
../../thrift/save.thrift
no changes added to commit (use "git add" and/or "git commit -a")
acs@80826ae841a9:~/thrift_lesson/match_system/src$ git add main.cpp
acs@80826ae841a9:~/thrift_lesson/match_system/src$ git add ../../game/src/client.py
acs@80826ae841a9:~/thrift_lesson/match_system/src$ git add ../../thrift/save.thrift
acs@80826ae841a9:~/thrift_lesson/match_system/src$ git add save_client/
acs@80826ae841a9:~/thrift_lesson/match_system/src$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: main.cpp
new file: save_client/Save.cpp
new file: save_client/Save.h
new file: save_client/save_types.h
new file: ../../thrift/save.thrift
Untracked files:
(use "git add <file>..." to include in what will be committed)
../../game/src/match_client/__pycache__/
../../game/src/match_client/match/__pycache__/
Match.o
Save.o
main
main.o
match_types.o
acs@80826ae841a9:~/thrift_lesson/match_system/src$ git commit -m "implement save-client"
[master ad9345f] implement save-client
5 files changed, 907 insertions(+), 1 deletion(-)
create mode 100644 match_system/src/save_client/Save.cpp
create mode 100644 match_system/src/save_client/Save.h
create mode 100644 match_system/src/save_client/save_types.h
create mode 100644 thrift/save.thrift
acs@80826ae841a9:~/thrift_lesson/match_system/src$ git push origin master
Enumerating objects: 16, done.
Counting objects: 100% (16/16), done.
Compressing objects: 100% (10/10), done.
Writing objects: 100% (11/11), 6.10 KiB | 2.03 MiB/s, done.
Total 11 (delta 1), reused 0 (delta 0)
To git.acwing.com:kkoyy459/thrift_lesson.git
269c41b..ad9345f master -> master
acs@80826ae841a9:~/thrift_lesson/match_system/src$
优化版匹配系统
acs@80826ae841a9:~/thrift_lesson/match_system/src$ vim main.cpp
acs@80826ae841a9:~/thrift_lesson/match_system/src$ cat main.cpp
// This autogenerated skeleton file illustrates how to build a server.
// You should copy it to another filename to avoid overwriting it.
#include "match_server/Match.h"
#include "save_client/Save.h"
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/server/TSimpleServer.h>
#include <thrift/transport/TServerSocket.h>
#include <thrift/transport/TBufferTransports.h>
#include <thrift/transport/TTransportUtils.h>
#include <thrift/transport/TSocket.h>
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <vector>
#include <unistd.h>
using namespace ::apache::thrift;
using namespace ::apache::thrift::protocol;
using namespace ::apache::thrift::transport;
using namespace ::apache::thrift::server;
using namespace ::match_service;
using namespace ::save_service;
using namespace std;
struct Task
{
User user;
string type;
};
struct MessageQueue
{
queue<Task> q;
mutex m;
condition_variable cv;
}message_queue;
class Pool
{
public:
void save_result(int a, int b)
{
printf("Match Result: %d %d\n", a, b);
std::shared_ptr<TTransport> socket(new TSocket("123.57.67.128", 9090));
std::shared_ptr<TTransport> transport(new TBufferedTransport(socket));
std::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
SaveClient client(protocol);
try {
transport->open();
int res = client.save_data("acs_11511", "92da7fd2", a, b);
if (!res) puts("success");
else puts("failed");
transport->close();
} catch (TException& tx) {
cout << "ERROR: " << tx.what() << endl;
}
}
void match()
{
while (users.size() > 1)
{
sort(users.begin(), users.end(), [&](User& a, User& b){
return a.score < b.score;
});
bool flag = true;
for (uint32_t i = 1; i < users.size(); i++)
{
auto a = users[i - 1], b = users[i];
if (b.score - a.score <= 50)
{
users.erase(users.begin() + i - 1, users.begin() + i + 1);
save_result(a.id, b.id);
flag = false;
break;
}
}
if (flag) break;
}
}
void add(User user)
{
users.push_back(user);
}
void remove(User user)
{
for (uint32_t i = 0; i < users.size(); i++)
if (users[i].id == user.id)
{
users.erase(users.begin() + i);
break;
}
}
private:
vector<User> users;
}pool;
class MatchHandler : virtual public MatchIf {
public:
MatchHandler() {
// Your initialization goes here
}
int32_t add_user(const User& user, const std::string& info) {
// Your implementation goes here
printf("add_user\n");
unique_lock<mutex> lck(message_queue.m);
message_queue.q.push({user, "add"});
message_queue.cv.notify_all();
return 0;
}
int32_t remove_user(const User& user, const std::string& info) {
// Your implementation goes here
printf("remove_user\n");
unique_lock<mutex> lck(message_queue.m);
message_queue.q.push({user, "remove"});
message_queue.cv.notify_all();
return 0;
}
};
void consume_task()
{
while (true)
{
unique_lock<mutex> lck(message_queue.m);
if (message_queue.q.empty())
{
// message_queue.cv.wait(lck);
lck.unlock();
pool.match();
sleep(1);
}
else
{
auto task = message_queue.q.front();
message_queue.q.pop();
lck.unlock();
if (task.type == "add") pool.add(task.user);
else if (task.type == "remove") pool.remove(task.user);
pool.match();
}
}
}
int main(int argc, char **argv) {
int port = 9090;
::std::shared_ptr<MatchHandler> handler(new MatchHandler());
::std::shared_ptr<TProcessor> processor(new MatchProcessor(handler));
::std::shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
::std::shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
::std::shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);
cout << "Start Match Server" << endl;
thread matching_thread(consume_task);
server.serve();
return 0;
}
acs@80826ae841a9:~/thrift_lesson/match_system/src$ g++ -c main.cpp # 因为我们修改了main.cpp的内容,所以需要重新编译一次main.cpp
acs@80826ae841a9:~/thrift_lesson/match_system/src$ g++ *.o -o main -lthrift -pthread # 把所有编译好的CPP文件链接起来,因为这里要用到thrift和thread的动态链接库,所以要加上-lthrift、-pthread
acs@80826ae841a9:~/thrift_lesson/match_system/src$
下面打开了三个Terminal
-
第一个Terminal
acs@80826ae841a9:~/thrift_lesson/match_system/src$ pwd /home/acs/thrift_lesson/match_system/src acs@80826ae841a9:~/thrift_lesson/match_system/src$ ls -l total 1760 -rw-rw-r-- 1 acs acs 318344 May 2 21:14 Match.o -rw-rw-r-- 1 acs acs 282384 May 5 20:00 Save.o -rwxrwxr-x 1 acs acs 466680 May 5 21:13 main -rw-rw-r-- 1 acs acs 5015 May 5 21:11 main.cpp -rw-rw-r-- 1 acs acs 671536 May 5 21:11 main.o drwxrwxr-x 2 acs acs 4096 May 2 21:09 match_server -rw-rw-r-- 1 acs acs 42648 May 2 21:14 match_types.o drwxrwxr-x 2 acs acs 4096 May 5 19:04 save_client acs@80826ae841a9:~/thrift_lesson/match_system/src$ ./main # 先把匹配节点的服务端启动 Start Match Server add_user add_user add_user Match Result: 3 1 success add_user remove_user add_user add_user Match Result: 6 4 success
-
第二个Terminal
acs@80826ae841a9:~/thrift_lesson/match_system/src$ cd ../../game/src/ acs@80826ae841a9:~/thrift_lesson/game/src$ ls -l total 8 -rw-rw-r-- 1 acs acs 1070 May 3 17:27 client.py drwxrwxr-x 4 acs acs 4096 May 3 16:32 match_client acs@80826ae841a9:~/thrift_lesson/game/src$ python3 client.py # 启动一次游戏节点的客户端,从终端读入参数,然后观察匹配节点的服务端有什么反应 add 1 1 1000 add 2 2 2000 add 3 3 999 add 4 4 3000 remove 2 2 2000 add 5 5 1999 add 6 6 2999
-
第三个Terminal
acs@80826ae841a9:~/thrift_lesson/match_system/src$ ssh myserver Welcome to AC Server * Tutorial: https://www.acwing.com/activity/content/57/ __ __________ __ ______ ___ _______ / \ / ______/ / \ \| || \ | |/ _____| / /\ \ | | | | /\ | || || \ \| || / ___ / /__\ \| | | | / \ | || || |\ \ || | |_ | / ______ \ \_____\ \/ /\ \/ /| || | \ || \____| | /_/ \_\_______\__/ \__/ |_||_| \_|\________/ acs_11511@acs:~$ cd homework/lesson_6/ acs_11511@acs:~/homework/lesson_6$ ls -l total 4 -rw-r--r-- 1 acs_11511 acs_11511 21 May 5 21:20 result.txt acs_11511@acs:~/homework/lesson_6$ cat result.txt # 查看数据存储节点是否成功把数据存储下来 result: 1 3 564ad18e acs_11511@acs:~/homework/lesson_6$ cat result.txt result: 4 6 1861a1c1 acs_11511@acs:~/homework/lesson_6$
acs@80826ae841a9:~/thrift_lesson/match_system/src$ pwd
/home/acs/thrift_lesson/match_system/src
acs@80826ae841a9:~/thrift_lesson/match_system/src$ ls -l
total 1760
-rw-rw-r-- 1 acs acs 318344 May 2 21:14 Match.o
-rw-rw-r-- 1 acs acs 282384 May 5 20:00 Save.o
-rwxrwxr-x 1 acs acs 466680 May 5 21:13 main
-rw-rw-r-- 1 acs acs 5015 May 5 21:11 main.cpp
-rw-rw-r-- 1 acs acs 671536 May 5 21:11 main.o
drwxrwxr-x 2 acs acs 4096 May 2 21:09 match_server
-rw-rw-r-- 1 acs acs 42648 May 2 21:14 match_types.o
drwxrwxr-x 2 acs acs 4096 May 5 19:04 save_client
acs@80826ae841a9:~/thrift_lesson/match_system/src$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: main.cpp
Untracked files:
(use "git add <file>..." to include in what will be committed)
../../game/src/match_client/__pycache__/
../../game/src/match_client/match/__pycache__/
Match.o
Save.o
main
main.o
match_types.o
no changes added to commit (use "git add" and/or "git commit -a")
acs@80826ae841a9:~/thrift_lesson/match_system/src$ git add main.cpp
acs@80826ae841a9:~/thrift_lesson/match_system/src$ git commit -m "match server:3.0"
[master 33f4422] match server:3.0
1 file changed, 22 insertions(+), 5 deletions(-)
acs@80826ae841a9:~/thrift_lesson/match_system/src$ git push origin master
Enumerating objects: 9, done.
Counting objects: 100% (9/9), done.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (5/5), 825 bytes | 412.00 KiB/s, done.
Total 5 (delta 1), reused 0 (delta 0)
To git.acwing.com:kkoyy459/thrift_lesson.git
ad9345f..33f4422 master -> master
acs@80826ae841a9:~/thrift_lesson/match_system/src$
强化版匹配系统
acs@80826ae841a9:~/thrift_lesson/match_system/src$ pwd
/home/acs/thrift_lesson/match_system/src
acs@80826ae841a9:~/thrift_lesson/match_system/src$ ls -l
total 1760
-rw-rw-r-- 1 acs acs 318344 May 2 21:14 Match.o
-rw-rw-r-- 1 acs acs 282384 May 5 20:00 Save.o
-rwxrwxr-x 1 acs acs 466680 May 5 21:13 main
-rw-rw-r-- 1 acs acs 5759 May 5 21:47 main.cpp
-rw-rw-r-- 1 acs acs 671536 May 5 21:11 main.o
drwxrwxr-x 2 acs acs 4096 May 2 21:09 match_server
-rw-rw-r-- 1 acs acs 42648 May 2 21:14 match_types.o
drwxrwxr-x 2 acs acs 4096 May 5 19:04 save_client
acs@80826ae841a9:~/thrift_lesson/match_system/src$ vim main.cpp
acs@80826ae841a9:~/thrift_lesson/match_system/src$ cat main.cpp
// This autogenerated skeleton file illustrates how to build a server.
// You should copy it to another filename to avoid overwriting it.
#include "match_server/Match.h"
#include "save_client/Save.h"
#include <thrift/concurrency/ThreadManager.h>
#include <thrift/concurrency/ThreadFactory.h>
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/server/TSimpleServer.h>
#include <thrift/server/TThreadedServer.h>
#include <thrift/transport/TServerSocket.h>
#include <thrift/transport/TBufferTransports.h>
#include <thrift/transport/TTransportUtils.h>
#include <thrift/transport/TSocket.h>
#include <thrift/TToString.h>
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <vector>
#include <unistd.h>
using namespace ::apache::thrift;
using namespace ::apache::thrift::protocol;
using namespace ::apache::thrift::transport;
using namespace ::apache::thrift::server;
using namespace ::match_service;
using namespace ::save_service;
using namespace std;
struct Task
{
User user;
string type;
};
struct MessageQueue
{
queue<Task> q;
mutex m;
condition_variable cv;
}message_queue;
class Pool
{
public:
void save_result(int a, int b)
{
printf("Match Result: %d %d\n", a, b);
std::shared_ptr<TTransport> socket(new TSocket("123.57.67.128", 9090));
std::shared_ptr<TTransport> transport(new TBufferedTransport(socket));
std::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
SaveClient client(protocol);
try {
transport->open();
int res = client.save_data("acs_11511", "92da7fd2", a, b);
if (!res) puts("success");
else puts("failed");
transport->close();
} catch (TException& tx) {
cout << "ERROR: " << tx.what() << endl;
}
}
void match()
{
while (users.size() > 1)
{
sort(users.begin(), users.end(), [&](User& a, User& b){
return a.score < b.score;
});
bool flag = true;
for (uint32_t i = 1; i < users.size(); i++)
{
auto a = users[i - 1], b = users[i];
if (b.score - a.score <= 50)
{
users.erase(users.begin() + i - 1, users.begin() + i + 1);
save_result(a.id, b.id);
flag = false;
break;
}
}
if (flag) break;
}
}
void add(User user)
{
users.push_back(user);
}
void remove(User user)
{
for (uint32_t i = 0; i < users.size(); i++)
if (users[i].id == user.id)
{
users.erase(users.begin() + i);
break;
}
}
private:
vector<User> users;
}pool;
class MatchHandler : virtual public MatchIf {
public:
MatchHandler() {
// Your initialization goes here
}
int32_t add_user(const User& user, const std::string& info) {
// Your implementation goes here
printf("add_user\n");
unique_lock<mutex> lck(message_queue.m);
message_queue.q.push({user, "add"});
message_queue.cv.notify_all();
return 0;
}
int32_t remove_user(const User& user, const std::string& info) {
// Your implementation goes here
printf("remove_user\n");
unique_lock<mutex> lck(message_queue.m);
message_queue.q.push({user, "remove"});
message_queue.cv.notify_all();
return 0;
}
};
class MatchCloneFactory : virtual public MatchIfFactory {
public:
~MatchCloneFactory() override = default;
MatchIf* getHandler(const ::apache::thrift::TConnectionInfo& connInfo) override
{
std::shared_ptr<TSocket> sock = std::dynamic_pointer_cast<TSocket>(connInfo.transport);
/*cout << "Incoming connection\n";
cout << "\tSocketInfo: " << sock->getSocketInfo() << "\n";
cout << "\tPeerHost: " << sock->getPeerHost() << "\n";
cout << "\tPeerAddress: " << sock->getPeerAddress() << "\n";
cout << "\tPeerPort: " << sock->getPeerPort() << "\n";*/
return new MatchHandler;
}
void releaseHandler(MatchIf* handler) override {
delete handler;
}
};
void consume_task()
{
while (true)
{
unique_lock<mutex> lck(message_queue.m);
if (message_queue.q.empty())
{
// message_queue.cv.wait(lck);
lck.unlock();
pool.match();
sleep(1);
}
else
{
auto task = message_queue.q.front();
message_queue.q.pop();
lck.unlock();
if (task.type == "add") pool.add(task.user);
else if (task.type == "remove") pool.remove(task.user);
pool.match();
}
}
}
int main(int argc, char **argv) {
TThreadedServer server(
std::make_shared<MatchProcessorFactory>(std::make_shared<MatchCloneFactory>()),
std::make_shared<TServerSocket>(9090), //port
std::make_shared<TBufferedTransportFactory>(),
std::make_shared<TBinaryProtocolFactory>());
cout << "Start Match Server" << endl;
thread matching_thread(consume_task);
server.serve();
return 0;
}
acs@80826ae841a9:~/thrift_lesson/match_system/src$ g++ -c main.cpp # 因为我们修改了main.cpp的内容,所以需要重新编译一次main.cpp
acs@80826ae841a9:~/thrift_lesson/match_system/src$ g++ *.o -o main -lthrift -pthread # 把所有编译好的CPP文件链接起来,因为这里要用到thrift和thread的动态链接库,所以要加上-lthrift、-pthread
acs@80826ae841a9:~/thrift_lesson/match_system/src$
下面打开了三个Terminal
-
第一个Terminal
acs@80826ae841a9:~/thrift_lesson/match_system/src$ pwd /home/acs/thrift_lesson/match_system/src acs@80826ae841a9:~/thrift_lesson/match_system/src$ ls -l total 1932 -rw-rw-r-- 1 acs acs 318344 May 2 21:14 Match.o -rw-rw-r-- 1 acs acs 282384 May 5 20:00 Save.o -rwxrwxr-x 1 acs acs 544600 May 6 11:04 main -rw-rw-r-- 1 acs acs 5763 May 6 11:04 main.cpp -rw-rw-r-- 1 acs acs 768440 May 6 11:04 main.o drwxrwxr-x 2 acs acs 4096 May 2 21:09 match_server -rw-rw-r-- 1 acs acs 42648 May 2 21:14 match_types.o drwxrwxr-x 2 acs acs 4096 May 5 19:04 save_client acs@80826ae841a9:~/thrift_lesson/match_system/src$ ./main # 先把匹配节点的服务端启动 Start Match Server add_user add_user Match Result: 1 2 success
-
第二个Terminal
acs@80826ae841a9:~/thrift_lesson/match_system/src$ cd ../../game/src/ acs@80826ae841a9:~/thrift_lesson/game/src$ ls -l total 8 -rw-rw-r-- 1 acs acs 1070 May 3 17:27 client.py drwxrwxr-x 4 acs acs 4096 May 3 16:32 match_client acs@80826ae841a9:~/thrift_lesson/game/src$ python3 client.py # 启动一次游戏节点的客户端,从终端读入参数,然后观察匹配节点的服务端有什么反应 add 1 1 1000 add 2 2 1000
-
第三个Terminal
acs@80826ae841a9:~/thrift_lesson/match_system/src$ ssh myserver Welcome to AC Server * Tutorial: https://www.acwing.com/activity/content/57/ __ __________ __ ______ ___ _______ / \ / ______/ / \ \| || \ | |/ _____| / /\ \ | | | | /\ | || || \ \| || / ___ / /__\ \| | | | / \ | || || |\ \ || | |_ | / ______ \ \_____\ \/ /\ \/ /| || | \ || \____| | /_/ \_\_______\__/ \__/ |_||_| \_|\________/ acs_11511@acs:~$ cd homework/lesson_6/ acs_11511@acs:~/homework/lesson_6$ ls -l total 4 -rw-r--r-- 1 acs_11511 acs_11511 21 May 6 14:02 result.txt acs_11511@acs:~/homework/lesson_6$ cat result.txt # 查看数据存储节点是否成功把数据存储下来 result: 1 2 141da30f acs_11511@acs:~/homework/lesson_6$
acs@80826ae841a9:~/thrift_lesson/match_system/src$ pwd
/home/acs/thrift_lesson/match_system/src
acs@80826ae841a9:~/thrift_lesson/match_system/src$ ls -l
total 1932
-rw-rw-r-- 1 acs acs 318344 May 2 21:14 Match.o
-rw-rw-r-- 1 acs acs 282384 May 5 20:00 Save.o
-rwxrwxr-x 1 acs acs 544600 May 6 11:04 main
-rw-rw-r-- 1 acs acs 5763 May 6 11:04 main.cpp
-rw-rw-r-- 1 acs acs 768440 May 6 11:04 main.o
drwxrwxr-x 2 acs acs 4096 May 2 21:09 match_server
-rw-rw-r-- 1 acs acs 42648 May 2 21:14 match_types.o
drwxrwxr-x 2 acs acs 4096 May 5 19:04 save_client
acs@80826ae841a9:~/thrift_lesson/match_system/src$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: main.cpp
Untracked files:
(use "git add <file>..." to include in what will be committed)
../../game/src/match_client/__pycache__/
../../game/src/match_client/match/__pycache__/
Match.o
Save.o
main
main.o
match_types.o
no changes added to commit (use "git add" and/or "git commit -a")
acs@80826ae841a9:~/thrift_lesson/match_system/src$ git add main.cpp
acs@80826ae841a9:~/thrift_lesson/match_system/src$ git commit -m "match server:4.0"
[master e9fcacf] match server:4.0
1 file changed, 27 insertions(+), 9 deletions(-)
acs@80826ae841a9:~/thrift_lesson/match_system/src$ git push origin master
Enumerating objects: 9, done.
Counting objects: 100% (9/9), done.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (5/5), 1.04 KiB | 1.04 MiB/s, done.
Total 5 (delta 1), reused 0 (delta 0)
To git.acwing.com:kkoyy459/thrift_lesson.git
33f4422..e9fcacf master -> master
acs@80826ae841a9:~/thrift_lesson/match_system/src$
终极版匹配系统
acs@80826ae841a9:~/thrift_lesson/match_system/src$ pwd
/home/acs/thrift_lesson/match_system/src
acs@80826ae841a9:~/thrift_lesson/match_system/src$ ls -l
total 1932
-rw-rw-r-- 1 acs acs 318344 May 2 21:14 Match.o
-rw-rw-r-- 1 acs acs 282384 May 5 20:00 Save.o
-rwxrwxr-x 1 acs acs 544600 May 6 11:04 main
-rw-rw-r-- 1 acs acs 6378 May 6 15:38 main.cpp
-rw-rw-r-- 1 acs acs 768440 May 6 11:04 main.o
drwxrwxr-x 2 acs acs 4096 May 2 21:09 match_server
-rw-rw-r-- 1 acs acs 42648 May 2 21:14 match_types.o
drwxrwxr-x 2 acs acs 4096 May 5 19:04 save_client
acs@80826ae841a9:~/thrift_lesson/match_system/src$ vim main.cpp
acs@80826ae841a9:~/thrift_lesson/match_system/src$ cat main.cpp
// This autogenerated skeleton file illustrates how to build a server.
// You should copy it to another filename to avoid overwriting it.
#include "match_server/Match.h"
#include "save_client/Save.h"
#include <thrift/concurrency/ThreadManager.h>
#include <thrift/concurrency/ThreadFactory.h>
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/server/TSimpleServer.h>
#include <thrift/server/TThreadedServer.h>
#include <thrift/transport/TServerSocket.h>
#include <thrift/transport/TBufferTransports.h>
#include <thrift/transport/TTransportUtils.h>
#include <thrift/transport/TSocket.h>
#include <thrift/TToString.h>
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <vector>
#include <unistd.h>
using namespace ::apache::thrift;
using namespace ::apache::thrift::protocol;
using namespace ::apache::thrift::transport;
using namespace ::apache::thrift::server;
using namespace ::match_service;
using namespace ::save_service;
using namespace std;
struct Task
{
User user;
string type;
};
struct MessageQueue
{
queue<Task> q;
mutex m;
condition_variable cv;
}message_queue;
class Pool
{
public:
void save_result(int a, int b)
{
printf("Match Result: %d %d\n", a, b);
std::shared_ptr<TTransport> socket(new TSocket("123.57.67.128", 9090));
std::shared_ptr<TTransport> transport(new TBufferedTransport(socket));
std::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
SaveClient client(protocol);
try {
transport->open();
int res = client.save_data("acs_11511", "92da7fd2", a, b);
if (!res) puts("success");
else puts("failed");
transport->close();
} catch (TException& tx) {
cout << "ERROR: " << tx.what() << endl;
}
}
bool check_match(uint32_t i, uint32_t j)
{
auto a = users[i], b = users[j];
int dt = abs(a.score - b.score);
int a_max_dif = wt[i] * 50;
int b_max_dif = wt[j] * 50;
return dt <= a_max_dif && dt <= b_max_dif;
}
void match()
{
for (uint32_t i = 0; i < wt.size(); i++)
wt[i]++;
while (users.size() > 1)
{
bool flag = true;
for (uint32_t i = 0; i < users.size(); i++)
{
for (uint32_t j = i + 1; j < users.size(); j++)
{
if (check_match(i, j))
{
auto a = users[i], b = users[j];
users.erase(users.begin() + j);
users.erase(users.begin() + i);
wt.erase(wt.begin() + j);
wt.erase(wt.begin() + i);
save_result(a.id, b.id);
flag = false;
break;
}
}
if (!flag) break;
}
if (flag) break;
}
}
void add(User user)
{
users.push_back(user);
wt.push_back(0);
}
void remove(User user)
{
for (uint32_t i = 0; i < users.size(); i++)
if (users[i].id == user.id)
{
users.erase(users.begin() + i);
wt.erase(wt.begin() + i);
break;
}
}
private:
vector<User> users;
vector<int> wt;
}pool;
class MatchHandler : virtual public MatchIf {
public:
MatchHandler() {
// Your initialization goes here
}
int32_t add_user(const User& user, const std::string& info) {
// Your implementation goes here
printf("add_user\n");
unique_lock<mutex> lck(message_queue.m);
message_queue.q.push({user, "add"});
message_queue.cv.notify_all();
return 0;
}
int32_t remove_user(const User& user, const std::string& info) {
// Your implementation goes here
printf("remove_user\n");
unique_lock<mutex> lck(message_queue.m);
message_queue.q.push({user, "remove"});
message_queue.cv.notify_all();
return 0;
}
};
class MatchCloneFactory : virtual public MatchIfFactory {
public:
~MatchCloneFactory() override = default;
MatchIf* getHandler(const ::apache::thrift::TConnectionInfo& connInfo) override
{
std::shared_ptr<TSocket> sock = std::dynamic_pointer_cast<TSocket>(connInfo.transport);
/*cout << "Incoming connection\n";
cout << "\tSocketInfo: " << sock->getSocketInfo() << "\n";
cout << "\tPeerHost: " << sock->getPeerHost() << "\n";
cout << "\tPeerAddress: " << sock->getPeerAddress() << "\n";
cout << "\tPeerPort: " << sock->getPeerPort() << "\n";*/
return new MatchHandler;
}
void releaseHandler(MatchIf* handler) override {
delete handler;
}
};
void consume_task()
{
while (true)
{
unique_lock<mutex> lck(message_queue.m);
if (message_queue.q.empty())
{
// message_queue.cv.wait(lck);
lck.unlock();
pool.match();
sleep(1);
}
else
{
auto task = message_queue.q.front();
message_queue.q.pop();
lck.unlock();
if (task.type == "add") pool.add(task.user);
else if (task.type == "remove") pool.remove(task.user);
}
}
}
int main(int argc, char **argv) {
TThreadedServer server(
std::make_shared<MatchProcessorFactory>(std::make_shared<MatchCloneFactory>()),
std::make_shared<TServerSocket>(9090), //port
std::make_shared<TBufferedTransportFactory>(),
std::make_shared<TBinaryProtocolFactory>());
cout << "Start Match Server" << endl;
thread matching_thread(consume_task);
server.serve();
return 0;
}
acs@80826ae841a9:~/thrift_lesson/match_system/src$ g++ -c main.cpp # 因为我们修改了main.cpp的内容,所以需要重新编译一次main.cpp
acs@80826ae841a9:~/thrift_lesson/match_system/src$ g++ *.o -o main -lthrift -pthread # 把所有编译好的CPP文件链接起来,因为这里要用到thrift和thread的动态链接库,所以要加上-lthrift、-pthread
acs@80826ae841a9:~/thrift_lesson/match_system/src$
下面打开了三个Terminal
-
第一个Terminal
acs@80826ae841a9:~/thrift_lesson/match_system/src$ pwd /home/acs/thrift_lesson/match_system/src acs@80826ae841a9:~/thrift_lesson/match_system/src$ ls -l total 1940 -rw-rw-r-- 1 acs acs 318344 May 2 21:14 Match.o -rw-rw-r-- 1 acs acs 282384 May 5 20:00 Save.o -rwxrwxr-x 1 acs acs 544576 May 6 15:41 main -rw-rw-r-- 1 acs acs 6378 May 6 15:41 main.cpp -rw-rw-r-- 1 acs acs 776648 May 6 15:41 main.o drwxrwxr-x 2 acs acs 4096 May 2 21:09 match_server -rw-rw-r-- 1 acs acs 42648 May 2 21:14 match_types.o drwxrwxr-x 2 acs acs 4096 May 5 19:04 save_client acs@80826ae841a9:~/thrift_lesson/match_system/src$ ./main # 先把匹配节点的服务端启动 Start Match Server add_user add_user add_user add_user Match Result: 3 4 success Match Result: 1 2 success
-
第二个Terminal
acs@80826ae841a9:~/thrift_lesson/match_system/src$ cd ../../game/src/ acs@80826ae841a9:~/thrift_lesson/game/src$ ls -l total 8 -rw-rw-r-- 1 acs acs 1070 May 3 17:27 client.py drwxrwxr-x 4 acs acs 4096 May 3 16:32 match_client acs@80826ae841a9:~/thrift_lesson/game/src$ python3 client.py # 启动一次游戏节点的客户端,从终端读入参数,然后观察匹配节点的服务端有什么反应 add 1 1 1000 add 2 2 2000 add 3 3 4000 add 4 4 4500
-
第三个Terminal
acs@80826ae841a9:~/thrift_lesson/match_system/src$ ssh myserver Welcome to AC Server * Tutorial: https://www.acwing.com/activity/content/57/ __ __________ __ ______ ___ _______ / \ / ______/ / \ \| || \ | |/ _____| / /\ \ | | | | /\ | || || \ \| || / ___ / /__\ \| | | | / \ | || || |\ \ || | |_ | / ______ \ \_____\ \/ /\ \/ /| || | \ || \____| | /_/ \_\_______\__/ \__/ |_||_| \_|\________/ acs_11511@acs:~$ cd homework/lesson_6/ acs_11511@acs:~/homework/lesson_6$ ls -l total 4 -rw-r--r-- 1 acs_11511 acs_11511 21 May 6 15:46 result.txt acs_11511@acs:~/homework/lesson_6$ cat result.txt # 查看数据存储节点是否成功把数据存储下来 result: 1 2 141da30f acs_11511@acs:~/homework/lesson_6$
acs@80826ae841a9:~/thrift_lesson/match_system/src$ pwd
/home/acs/thrift_lesson/match_system/src
acs@80826ae841a9:~/thrift_lesson/match_system/src$ ls -l
total 1940
-rw-rw-r-- 1 acs acs 318344 May 2 21:14 Match.o
-rw-rw-r-- 1 acs acs 282384 May 5 20:00 Save.o
-rwxrwxr-x 1 acs acs 544576 May 6 15:41 main
-rw-rw-r-- 1 acs acs 6378 May 6 15:41 main.cpp
-rw-rw-r-- 1 acs acs 776648 May 6 15:41 main.o
drwxrwxr-x 2 acs acs 4096 May 2 21:09 match_server
-rw-rw-r-- 1 acs acs 42648 May 2 21:14 match_types.o
drwxrwxr-x 2 acs acs 4096 May 5 19:04 save_client
acs@80826ae841a9:~/thrift_lesson/match_system/src$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: main.cpp
Untracked files:
(use "git add <file>..." to include in what will be committed)
../../game/src/match_client/__pycache__/
../../game/src/match_client/match/__pycache__/
Match.o
Save.o
main
main.o
match_types.o
no changes added to commit (use "git add" and/or "git commit -a")
acs@80826ae841a9:~/thrift_lesson/match_system/src$ git add main.cpp
acs@80826ae841a9:~/thrift_lesson/match_system/src$ git commit -m "match server:5.0"
[master d2029c5] match server:5.0
1 file changed, 32 insertions(+), 13 deletions(-)
acs@80826ae841a9:~/thrift_lesson/match_system/src$ git push origin master
Enumerating objects: 9, done.
Counting objects: 100% (9/9), done.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (5/5), 922 bytes | 461.00 KiB/s, done.
Total 5 (delta 1), reused 0 (delta 0)
To git.acwing.com:kkoyy459/thrift_lesson.git
e9fcacf..d2029c5 master -> master
acs@80826ae841a9:~/thrift_lesson/match_system/src$
管道、环境变量与常用命令
管道
-
管道:类似于文件重定向,可以将前一个命令的stdout(标准输出)重定向到下一个命令的stdin(标准输入)
-
管道命令仅处理stdout(标准输出),会忽略stderr(标准错误输出)
-
管道右边的命令必须要能接受stdin(标准输入)
-
多个管道命令可以串联
-
管道与文件重定向的区别
-
文件重定向:左边为命令,右边为文件
-
管道:左右两边均为命令,左边有stdout(标准输出),右边有stdin(标准输入)
-
例子
acs@80826ae841a9:~/homework/lesson_6/thrift_lesson/game/src$ pwd
/home/acs/homework/lesson_6/thrift_lesson/game/src
acs@80826ae841a9:~/homework/lesson_6/thrift_lesson/game/src$ ls -l
total 8
-rw-rw-r-- 1 acs acs 1068 May 7 10:13 client.py
drwxrwxr-x 4 acs acs 4096 May 6 19:37 match_client
acs@80826ae841a9:~/homework/lesson_6/thrift_lesson/game/src$ find . -name '*.py' | xargs cat | wc -l # 统计当前目录及其子目录下的所有.py文件的总行数
643
acs@80826ae841a9:~/homework/lesson_6/thrift_lesson/game/src$
环境变量
在Linux系统中,有的配置信息记录在文件中,有的配置信息记录在环境变量中
-
环境变量
- 在Linux系统中,会用很多环境变量来记录配置信息,我们可以通过修改环境变量来方便地修改配置信息
- 环境变量(类似于全局变量)可以被各个进程访问到
-
显示环境变量
-
env
acs@80826ae841a9:~$ pwd /home/acs acs@80826ae841a9:~$ ls -l total 16 drwxrwxr-x 8 acs acs 4096 May 6 19:04 homework drwxrwxr-x 2 acs acs 4096 Sep 25 2023 temp -rwxrwxr-x 1 acs acs 103 Dec 31 21:00 test.sh drwxrwxr-x 6 acs acs 4096 Jan 2 23:24 thrift_lesson acs@80826ae841a9:~$ env # 显示当前的环境变量 SHELL=/bin/bash TMUX=/tmp/tmux-1000/default,870,0 PWD=/home/acs LOGNAME=acs MOTD_SHOWN=pam HOME=/home/acs LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.wim=01;31:*.swm=01;31:*.dwm=01;31:*.esd=01;31:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36: SSH_CONNECTION=182.92.217.102 53920 172.17.0.13 22 LESSCLOSE=/usr/bin/lesspipe %s %s TERM=screen LESSOPEN=| /usr/bin/lesspipe %s USER=acs TMUX_PANE=%0 SHLVL=2 SSH_CLIENT=182.92.217.102 53920 22 PATH=/home/acs/.homework:/home/acs/.homework:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin SSH_TTY=/dev/pts/1 _=/usr/bin/env OLDPWD=/home/acs/homework/lesson_6/thrift_lesson/game/src acs@80826ae841a9:~$
-
set
acs@80826ae841a9:~$ pwd /home/acs acs@80826ae841a9:~$ ls -l total 16 drwxrwxr-x 8 acs acs 4096 May 6 19:04 homework drwxrwxr-x 2 acs acs 4096 Sep 25 2023 temp -rwxrwxr-x 1 acs acs 103 Dec 31 21:00 test.sh drwxrwxr-x 6 acs acs 4096 Jan 2 23:24 thrift_lesson acs@80826ae841a9:~$ set # 显示当前的Shell变量和函数 BASH=/bin/bash BASHOPTS=checkwinsize:cmdhist:complete_fullquote:expand_aliases:extquote:force_fignore:globasciiranges:histappend:hostcomplete:interactive_comments:login_shell:progcomp:promptvars:sourcepath BASH_ALIASES=() BASH_ARGC=([0]="0") BASH_ARGV=() BASH_CMDS=() BASH_LINENO=() BASH_SOURCE=() BASH_VERSINFO=([0]="5" [1]="0" [2]="17" [3]="1" [4]="release" [5]="x86_64-pc-linux-gnu") BASH_VERSION='5.0.17(1)-release' COLUMNS=190 DIRSTACK=() EUID=1000 GROUPS=() HISTCONTROL=ignoreboth HISTFILE=/home/acs/.bash_history HISTFILESIZE=2000 HISTSIZE=1000 HOME=/home/acs HOSTNAME=80826ae841a9 HOSTTYPE=x86_64 IFS=$' \t\n' LESSCLOSE='/usr/bin/lesspipe %s %s' LESSOPEN='| /usr/bin/lesspipe %s' LINES=41 LOGNAME=acs LS_COLORS='rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.wim=01;31:*.swm=01;31:*.dwm=01;31:*.esd=01;31:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:' MACHTYPE=x86_64-pc-linux-gnu MAILCHECK=60 MOTD_SHOWN=pam OPTERR=1 OPTIND=1 OSTYPE=linux-gnu PATH=/home/acs/.homework:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin PIPESTATUS=([0]="0") PPID=853 PS1='\[\e]0;\u@\h: \w\a\]${debian_chroot:+($debian_chroot)}\u@\h:\w\$ ' PS2='> ' PS4='+ ' PWD=/home/acs SHELL=/bin/bash SHELLOPTS=braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor SHLVL=1 SSH_CLIENT='182.92.217.102 53920 22' SSH_CONNECTION='182.92.217.102 53920 172.17.0.13 22' SSH_TTY=/dev/pts/1 TERM=xterm UID=1000 USER=acs _=clear acs@80826ae841a9:~$
-
export
acs@80826ae841a9:~$ pwd /home/acs acs@80826ae841a9:~$ ls -l total 16 drwxrwxr-x 8 acs acs 4096 May 6 19:04 homework drwxrwxr-x 2 acs acs 4096 Sep 25 2023 temp -rwxrwxr-x 1 acs acs 103 Dec 31 21:00 test.sh drwxrwxr-x 6 acs acs 4096 Jan 2 23:24 thrift_lesson acs@80826ae841a9:~$ export # 显示当前已经设置为环境变量的变量列表 declare -x HOME="/home/acs" declare -x LESSCLOSE="/usr/bin/lesspipe %s %s" declare -x LESSOPEN="| /usr/bin/lesspipe %s" declare -x LOGNAME="acs" declare -x LS_COLORS="rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.wim=01;31:*.swm=01;31:*.dwm=01;31:*.esd=01;31:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:" declare -x MOTD_SHOWN="pam" declare -x OLDPWD declare -x PATH="/home/acs/.homework:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin" declare -x PWD="/home/acs" declare -x SHELL="/bin/bash" declare -x SHLVL="1" declare -x SSH_CLIENT="182.92.217.102 53920 22" declare -x SSH_CONNECTION="182.92.217.102 53920 172.17.0.13 22" declare -x SSH_TTY="/dev/pts/1" declare -x TERM="xterm" declare -x USER="acs" acs@80826ae841a9:~$ echo $PATH # 输出环境变量PATH的值 /home/acs/.homework:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin acs@80826ae841a9:~$
-
-
环境变量的定义、修改、删除操作,可以参考《shell语法》这一章节中的知识点,这里就不再过多的赘述
-
将,对环境变量的修改,应用到未来的所有环境下(即持久化)
-
没有持久化的例子,当你重新打开一个新的Terminal的时候,会发现环境变量HOME的值没有改变
acs@80826ae841a9:~$ cd ~ acs@80826ae841a9:~$ pwd /home/acs acs@80826ae841a9:~$ ls -l total 16 drwxrwxr-x 8 acs acs 4096 May 6 19:04 homework drwxrwxr-x 2 acs acs 4096 Sep 25 2023 temp -rwxrwxr-x 1 acs acs 103 Dec 31 21:00 test.sh drwxrwxr-x 6 acs acs 4096 Jan 2 23:24 thrift_lesson acs@80826ae841a9:~$ echo $HOME /home/acs acs@80826ae841a9:~$ export HOME="/home/acs/homework" # 修改环境变量HOME的值 acs@80826ae841a9:/home/acs$ cd ~ acs@80826ae841a9:~$ pwd /home/acs/homework acs@80826ae841a9:~$ ls -l total 24 drwxrwxr-x 12 acs acs 4096 May 2 15:56 lesson_1 drwxrwxr-x 12 acs acs 4096 Aug 4 2023 lesson_2 drwxrwxr-x 7 acs acs 4096 Sep 7 2023 lesson_3 drwxrwxr-x 7 acs acs 4096 Sep 18 2023 lesson_4 drwxrwxr-x 3 acs acs 4096 Dec 31 18:44 lesson_5 drwxrwxr-x 3 acs acs 4096 May 6 19:04 lesson_6 acs@80826ae841a9:~$
-
持久化的例子,当你重新打开一个新的Terminal的时候,会发现环境变量HOME的值已经改变
acs@80826ae841a9:~$ cd ~ acs@80826ae841a9:~$ pwd /home/acs acs@80826ae841a9:~$ ls -al total 172 drwxr-xr-x 1 acs acs 4096 May 12 18:37 . drwxr-xr-x 1 root root 4096 Jul 23 2021 .. -rw------- 1 acs acs 20722 May 12 18:37 .bash_history -rw-r--r-- 1 acs acs 220 Jul 23 2021 .bash_logout -rw-r--r-- 1 acs acs 3831 May 15 2023 .bashrc drwx------ 2 acs acs 4096 Jul 24 2023 .cache drwx------ 3 acs acs 4096 Jul 27 2023 .config -rw-rw-r-- 1 acs acs 48 Dec 31 20:14 .gitconfig drwxrwxr-x 1 acs acs 4096 Jul 27 2023 .homework drwxr-xr-x 1 acs acs 4096 Jul 23 2021 .ipython -rw-r--r-- 1 acs acs 807 Jul 23 2021 .profile -rw------- 1 acs acs 7 Aug 17 2021 .python_history drwx------ 1 acs acs 4096 Sep 26 2023 .ssh -rw-r--r-- 1 acs acs 0 Jul 23 2021 .sudo_as_admin_successful -rw-r--r-- 1 acs acs 1569 May 15 2023 .tmux.conf drwxr-xr-x 1 acs acs 4096 Sep 9 2021 .vim -rw------- 1 acs acs 49564 May 7 10:17 .viminfo -rw-r--r-- 1 acs acs 6128 May 15 2023 .vimrc drwxrwxr-x 8 acs acs 4096 May 6 19:04 homework drwxrwxr-x 2 acs acs 4096 Sep 25 2023 temp -rwxrwxr-x 1 acs acs 103 Dec 31 21:00 test.sh drwxrwxr-x 6 acs acs 4096 Jan 2 23:24 thrift_lesson acs@80826ae841a9:~$ vim .bashrc # 在.bashrc文件的最后一行中,加上export HOME=/home/acs/homework acs@80826ae841a9:~$ cat .bashrc # ~/.bashrc: executed by bash(1) for non-login shells. # see /usr/share/doc/bash/examples/startup-files (in the package bash-doc) # for examples # If not running interactively, don't do anything case $- in *i*) ;; *) return;; esac # don't put duplicate lines or lines starting with space in the history. # See bash(1) for more options HISTCONTROL=ignoreboth # append to the history file, don't overwrite it shopt -s histappend # for setting history length see HISTSIZE and HISTFILESIZE in bash(1) HISTSIZE=1000 HISTFILESIZE=2000 # check the window size after each command and, if necessary, # update the values of LINES and COLUMNS. shopt -s checkwinsize # If set, the pattern "**" used in a pathname expansion context will # match all files and zero or more directories and subdirectories. #shopt -s globstar # make less more friendly for non-text input files, see lesspipe(1) [ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)" # set variable identifying the chroot you work in (used in the prompt below) if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then debian_chroot=$(cat /etc/debian_chroot) fi # set a fancy prompt (non-color, unless we know we "want" color) case "$TERM" in xterm-color|*-256color) color_prompt=yes;; esac # uncomment for a colored prompt, if the terminal has the capability; turned # off by default to not distract the user: the focus in a terminal window # should be on the output of commands, not on the prompt #force_color_prompt=yes if [ -n "$force_color_prompt" ]; then if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then # We have color support; assume it's compliant with Ecma-48 # (ISO/IEC-6429). (Lack of such support is extremely rare, and such # a case would tend to support setf rather than setaf.) color_prompt=yes else color_prompt= fi fi if [ "$color_prompt" = yes ]; then PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ ' else PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ ' fi unset color_prompt force_color_prompt # If this is an xterm set the title to user@host:dir case "$TERM" in xterm*|rxvt*) PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1" ;; *) ;; esac # enable color support of ls and also add handy aliases if [ -x /usr/bin/dircolors ]; then test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)" alias ls='ls --color=auto' #alias dir='dir --color=auto' #alias vdir='vdir --color=auto' alias grep='grep --color=auto' alias fgrep='fgrep --color=auto' alias egrep='egrep --color=auto' fi # colored GCC warnings and errors #export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01' # some more ls aliases alias ll='ls -alF' alias la='ls -A' alias l='ls -CF' # Add an "alert" alias for long running commands. Use like so: # sleep 10; alert alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"' # Alias definitions. # You may want to put all your additions into a separate file like # ~/.bash_aliases, instead of adding them here directly. # See /usr/share/doc/bash-doc/examples in the bash-doc package. if [ -f ~/.bash_aliases ]; then . ~/.bash_aliases fi # enable programmable completion features (you don't need to enable # this, if it's already enabled in /etc/bash.bashrc and /etc/profile # sources /etc/bash.bashrc). if ! shopt -oq posix; then if [ -f /usr/share/bash-completion/bash_completion ]; then . /usr/share/bash-completion/bash_completion elif [ -f /etc/bash_completion ]; then . /etc/bash_completion fi fi export PATH=/home/acs/.homework:$PATH alias tmux='tmux -u' export HOME=/home/acs/homework acs@80826ae841a9:~$ source .bashrc # 引入.bashrc文件 acs@80826ae841a9:/home/acs$ cd ~ acs@80826ae841a9:~$ pwd /home/acs/homework acs@80826ae841a9:~$ ls -al total 36 drwxrwxr-x 8 acs acs 4096 May 6 19:04 . drwxr-xr-x 1 acs acs 4096 May 12 18:40 .. drwxrwxr-x 12 acs acs 4096 May 2 15:56 lesson_1 drwxrwxr-x 12 acs acs 4096 Aug 4 2023 lesson_2 drwxrwxr-x 7 acs acs 4096 Sep 7 2023 lesson_3 drwxrwxr-x 7 acs acs 4096 Sep 18 2023 lesson_4 drwxrwxr-x 3 acs acs 4096 Dec 31 18:44 lesson_5 drwxrwxr-x 3 acs acs 4096 May 6 19:04 lesson_6 acs@80826ae841a9:~$
-
-
为什么这样做,可以,**将,对环境变量的修改,应用到未来的所有环境下(即持久化)**呢?
- 因为
- 每次ssh登陆远程服务器时,都会先启动一个bash命令行给我们
- 每次启动bash时,都会先执行.bashrc
- 每次tmux新开一个pane时,都会先启动一个bash命令行给我们
- 每次启动bash时,都会先执行.bashrc
- 每次ssh登陆远程服务器时,都会先启动一个bash命令行给我们
- 因此未来所有新开的环境都会先加载我们修改的内容
- 所以可以实现持久化
- 因为
-
常见的环境变量
-
HOME:用户的家目录
acs@80826ae841a9:~$ echo $HOME /home/acs acs@80826ae841a9:~$
-
PATH:用于指定可执行文件的路径
- 路径与路径之间用冒号隔开
- 当需要执行某个可执行文件,但某个可执行文件同时出现在多个路径中时,按照从左到右的优先顺序,优先选择第一个路径下的可执行文件进行执行
acs@80826ae841a9:~$ echo $PATH /home/acs/.homework:/home/acs/.homework:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin acs@80826ae841a9:~$
-
LD_LIBRARY_PATH:用于指定动态链接库(.so文件)的路径,其内容是以冒号分隔的路径列表**(按照从左到右的优先顺序)**
acs@80826ae841a9:~$ echo $LD_LIBRARY_PATH acs@80826ae841a9:~$
-
C_INCLUDE_PATH:用于指定C语言的头文件的路径,其内容是以冒号分隔的路径列表**(按照从左到右的优先顺序)**
acs@80826ae841a9:/$ echo $C_INCLUDE_PATH acs@80826ae841a9:/$
-
CPLUS_INCLUDE_PATH:用于指定CPP的头文件的路径,其内容是以冒号分隔的路径列表**(按照从左到右的优先顺序)**
acs@80826ae841a9:/$ echo $CPLUS_INCLUDE_PATH acs@80826ae841a9:/$
-
PYTHONPATH:用于指定Python导入包的路径,其内容是以冒号分隔的路径列表**(按照从左到右的优先顺序)**
acs@80826ae841a9:/$ echo $PYTHONPATH acs@80826ae841a9:/$
-
JAVA_HOME:JDK的安装目录
acs@80826ae841a9:/$ echo $JAVA_HOME acs@80826ae841a9:/$
-
CLASSPATH:用于指定Java导入类的路径,其内容是以冒号分隔的路径列表**(按照从左到右的优先顺序)**
acs@80826ae841a9:/$ echo $CLASSPATH acs@80826ae841a9:/$
-
常用命令
-
Linux命令非常多,本节讲解几个常用命令。其他命令依赖于大家根据实际操作环境,现用现查即可。
-
系统状况相关的命令
- top:查看前几个进程的信息(类似于任务管理器)
- 打开后,键盘按下M:按使用内存排序
- 打开后,键盘按下P:按使用CPU排序
- 打开后,键盘按下q:退出
- df -h:查看硬盘使用情况
- free -h:查看内存使用情况
- du -sh:查看当前目录占用的硬盘空间
- ps aux:查看所有进程
- kill -9 pid:杀死进程编号为pid的进程
- kill -s SIGTERM pid:传递某个具体的信号,杀死进程编号为pid的进程
- netstat -nt:查看所有网络连接
- w:列出当前登陆的用户
- ping www.baidu.com:检查是否连网
- top:查看前几个进程的信息(类似于任务管理器)
-
文件权限相关的命令
- chmod +x file:给文件名为file的文件添加可执行权限
- chmod -x file:去掉文件名为file的文件的可执行权限
- chmod 777 file:将文件名为file的文件的权限状态改成777
- chmod 777 file -R:递归修改目录名为file的目录的权限
-
文件检索相关的命令
- find path -name ‘*.py’:搜索目录名为path的目录及其子目录下的所有.py文件
- grep xxx:从stdin(标准输入)中读取若干行内容,如果某行的内容中包含xxx,则输出该行,否则忽略该行,键盘按下CTRL + d即可退出
- wc:从stdin(标准输入)中直接读取内容,键盘按下CTRL + d即可退出
- wc file:统计文件名为file的文件中的行数、单词数、字节数
- wc -l file:统计文件名为file的文件中的行数
- wc -w file:统计文件名为file的文件中的单词数
- wc -c file:统计文件名为file的文件中的字节数
- tree:展示当前目录的文件结构
- tree path:展示目录名为path的目录的文件结构
- tree -a:展示隐藏文件
- ag xxx:从当前目录及其子目录下的所有文件中检索出xxx,并且分别说明是在哪个文件的哪一行,这个命令很好使!!!
- cut命令,分割内容,从stdin(标准输入)中读取多行数据
- echo $PATH | cut -d ‘:’ -f 3,5:输出环境变量PATH根据冒号分割后的第3块和第5块的内容
- echo $PATH | cut -d ‘:’ -f 3-5:输出环境变量PATH根据冒号分割后的第3块到第5块的所有内容
- echo $PATH | cut -c 3,5:输出环境变量PATH第3个和第5个字符
- echo $PATH | cut -c 3-5:输出环境变量PATH第3个到第5个的所有字符
- sort:从stdin(标准输入)中读取若干行内容,将每行内容按字典序排序,键盘按下CTRL + d即可退出
- sort file:将文件名为file的文件中的每行内容按字典序排序
- xargs的作用是,将stdin(标准输入)中的内容根据空格或回车分割,分割后的内容作为后面的那个命令的参数
- find . -name ‘*.py’ | xargs cat | wc -l:统计当前目录及其子目录下的所有.py文件的总行数
-
查看文件内容相关的命令
- more file:浏览文件名为file的文件的内容
- 键盘按下回车,查看下一行
- 键盘按下空格,查看下一页
- 键盘按下b,查看上一页
- 键盘按下q,即可退出
- less file:浏览文件名为file的文件的内容
- 键盘按下回车,查看下一行
- 键盘按下y,查看上一行
- 键盘按下Page Down,查看下一页
- 键盘按下Page Up,查看上一页
- 键盘按下q,即可退出
- head -3 file:展示文件名为file的文件的前3行内容
- 支持从stdin(标准输入)中读取内容,键盘按下CTRL + d即可退出
- tail -3 file:展示文件名为file的文件的末尾3行内容
- 支持从stdin(标准输入)中读取内容,键盘按下CTRL + d即可退出
- more file:浏览文件名为file的文件的内容
-
用户相关的命令
- history:展示当前用户的最近1000条的历史操作,内容存放在家目录下的.bash_history文件中
-
工具相关的命令
-
md5sum:可以从stdin(标准输入)中读取内容,然后键盘按下回车,然后键盘按下CTRL + d,即可得到内容的哈希值
- md5sum file:得到文件名为file的文件的哈希值
-
time command:统计命令为command的命令的执行时间
-
ipython3:打开一个交互式的python3环境
-
可以当计算器用
acs@80826ae841a9:~$ ipython3 Python 3.8.10 (default, Jun 2 2021, 10:49:15) Type 'copyright', 'credits' or 'license' for more information IPython 7.13.0 -- An enhanced Interactive Python. Type '?' for help. In [1]: (3 + 1) * (4 + 2) # 算加法 Out[1]: 24 In [2]: 4 / 3 # 算除法 Out[2]: 1.3333333333333333 In [3]: 4 // 3 # 算除法,整除 Out[3]: 1 In [4]: 2 ** 3 # 2的3次方 Out[4]: 8 In [5]: 2 ** 64 # 2的64次方 Out[5]: 18446744073709551616 In [6]: 2 ** 128 # 2的128次方,可见是支持高精度的 Out[6]: 340282366920938463463374607431768211456 In [7]: exit acs@80826ae841a9:~$
-
可以执行shell脚本
acs@80826ae841a9:~$ ipython3 Python 3.8.10 (default, Jun 2 2021, 10:49:15) Type 'copyright', 'credits' or 'license' for more information IPython 7.13.0 -- An enhanced Interactive Python. Type '?' for help. In [1]: var = 2 ** 111 + 3 ** 78 In [2]: ! echo $var # 可以执行shell脚本,在ipython3中,!后面会被解析成shell脚本 16425799416689925560045733048873865337 In [3]: exit acs@80826ae841a9:~$
-
-
watch -n 0.1 command:每隔0.1秒执行一次命令为command的命令,键盘按下CTRL + c即可退出
-
tar命令
-
可以压缩文件
acs@80826ae841a9:~$ pwd /home/acs acs@80826ae841a9:~$ ls -l total 16 drwxrwxr-x 9 acs acs 4096 May 12 19:15 homework drwxrwxr-x 2 acs acs 4096 Sep 25 2023 temp -rwxrwxr-x 1 acs acs 103 Dec 31 21:00 test.sh drwxrwxr-x 6 acs acs 4096 Jan 2 23:24 thrift_lesson acs@80826ae841a9:~$ tar -zcvf ttt.tar.gz temp/* # 压缩整个目录 temp/temp.cpp temp/temp.sh temp/test.sh acs@80826ae841a9:~$ ls -l total 20 drwxrwxr-x 9 acs acs 4096 May 12 19:15 homework drwxrwxr-x 2 acs acs 4096 Sep 25 2023 temp -rwxrwxr-x 1 acs acs 103 Dec 31 21:00 test.sh drwxrwxr-x 6 acs acs 4096 Jan 2 23:24 thrift_lesson -rw-rw-r-- 1 acs acs 323 May 14 20:10 ttt.tar.gz acs@80826ae841a9:~$
-
可以解压压缩包
acs@80826ae841a9:~$ pwd /home/acs acs@80826ae841a9:~$ ls -l total 16 drwxrwxr-x 9 acs acs 4096 May 12 19:15 homework -rwxrwxr-x 1 acs acs 103 Dec 31 21:00 test.sh drwxrwxr-x 6 acs acs 4096 Jan 2 23:24 thrift_lesson -rw-rw-r-- 1 acs acs 323 May 14 20:10 ttt.tar.gz acs@80826ae841a9:~$ tar -zxvf ttt.tar.gz # 解压压缩包 temp/temp.cpp temp/temp.sh temp/test.sh acs@80826ae841a9:~$ ls -l total 20 drwxrwxr-x 9 acs acs 4096 May 12 19:15 homework drwxrwxr-x 2 acs acs 4096 May 14 20:13 temp -rwxrwxr-x 1 acs acs 103 Dec 31 21:00 test.sh drwxrwxr-x 6 acs acs 4096 Jan 2 23:24 thrift_lesson -rw-rw-r-- 1 acs acs 323 May 14 20:10 ttt.tar.gz acs@80826ae841a9:~$
-
-
diff file1 file2:查找文件名为file1的文件与文件名为file2的文件的不同点
-
-
安装软件相关的命令
- sudo command:以root的身份执行命令为command的命令,需要输入当前用户的密码才可以
- apt-get install xxx:安装名字为xxx的软件
- pip install xxx --user --upgrade:安装名字为xxx的包,–user表示将软件包安装到当前用户的主目录下
租云服务器及配环境
概述
云平台的作用
- 存放我们的docker容器,让计算跑在云端
- 我们未来的主要开发环境是在租的云服务器上的docker容器中。因为云服务器上的docker容器相当于是在云服务器里面再建一个虚拟的云服务器,这个虚拟的云服务器,即docker容器,具有独立性,可迁移性!!!
- 获得公网IP地址,让每个人可以访问到我们的服务
我们未来租的云服务器大致可分为两种
- 毛坯服务器,可定制化比较强,可以根据自己的需求搭建。一般是各种框架、thrift等会跑在这种需要自己搭建环境的服务器上
- 精装服务器,已经提供好各种服务,一般都是一些标准化的东西,我们拿来直接用即可。一般是通过socket、http等形式使用服务
任选一个云平台(阿里云,腾讯云,华为云)即可,推荐配置如下
-
CPU:1核,内存:2GB,硬盘空间:25G(后期可以动态扩容,前期配置低一些也没关系)
-
网络带宽采用按量付费,最大带宽拉满即可(费用取决于用量,与最大带宽无关)
-
系统版本:Ubuntu 20.04 LTS(推荐用统一版本,避免后期出现配置不兼容的问题)
-
云服务器一般要开放以下端口
-
80(HTTP)
-
443(HTTPS)
-
22(SSH)
-
租腾讯云云服务器及配环境
前提:已经租好腾讯云云服务器,且22端口已经开放
-
在AC Terminal上,通过ssh登录已经租好的腾讯云云服务器
ssh ubuntu@xxx.xxx.xxx.xxx # 注意,腾讯云云服务器默认分配的是ubuntu用户,而不是root用户。xxx.xxx.xxx.xxx为云服务器的公网IP
-
在腾讯云云服务器上,创建acs用户,并且授予acs用户sudo权限
sudo adduser acs # 创建acs用户,密码和ubuntu用户的密码一样。因为当前使用的是ubuntu用户,所以最前面要加上sudo sudo usermod -aG sudo acs # 给acs用户分配sudo权限。因为当前使用的是ubuntu用户,所以最前面要加上sudo
-
在腾讯云云服务器上,切换到acs用户,验证一下是否创建acs用户成功
su acs
-
在AC Terminal上,配置免密登录方式,登录云服务器(直接进入acs用户),详细操作可以参考《ssh》这一章节中的知识点,这里就不再过多的赘述
-
在AC Terminal上,通过ssh登录已经租好的腾讯云云服务器
ssh cgwserver # 登录云服务器(直接进入acs用户)
-
在腾讯云云服务器上,安装tmux
sudo apt-get update # 安装新软件前先执行这个命令,是为了确保你的系统获取到最新的软件包信息,以便在安装新软件时使用最新版本的软件包,以确保你安装的软件是最新的版本 sudo apt-get install tmux # 安装tmux
-
在AC Terminal上,将AC Terminal的配置传到腾讯云云服务器上,可以让腾讯云云服务器的基本使用环境和AC Terminal一致
scp .bashrc .vimrc .tmux.conf cgwserver:/home/acs/
-
在腾讯云云服务器上,打开tmux(养成好习惯,所有工作都在tmux里进行,防止意外关闭终端后,工作进度丢失),然后在tmux中安装docker(安装教程参考docker官网:Install Docker Engine on Ubuntu | Docker Docs)
-
安装完成后,可以查看下docker的版本
docker --version # 安装完成后,可以查看下docker的版本
-
Docker
在AC Terminal上,已经有相对应的docker镜像可供我们在云服务器上使用
acs@80826ae841a9:/var/lib/acwing/docker/images$ pwd
/var/lib/acwing/docker/images
acs@80826ae841a9:/var/lib/acwing/docker/images$ ls -lh
total 1.8G
-rw-r--r-- 1 acs acs 1.5G Oct 28 2021 django_lesson_1_0.tar # 这是Django框架课的镜像,报了名才会有
-rw-r--r-- 1 acs acs 301M Oct 18 2021 docker_lesson_1_0.tar # 这是Linux基础课的镜像,报了名才会有
acs@80826ae841a9:/var/lib/acwing/docker/images$
-
在腾讯云云服务器上,为了避免每次使用docker命令都需要加上sudo权限,可以将当前用户加入到安装docker的过程中自动创建的docker用户组里面(详情请参考docker官网:Linux post-installation steps for Docker Engine | Docker Docs)
sudo usermod -aG docker $USER
执行完此操作后,需要退出服务器,再重新登录回来,才可以省去sudo权限
-
docker
- 镜像(image),可能会存在多个镜像,这些镜像的相同部分,在docker中只会存储一份,这是docker的空间优化机制
- 容器(container),用相同的镜像生成的容器的环境都完全一样,容器修改完成后,也可以制作成一个镜像
- 镜像(image),可能会存在多个镜像,这些镜像的相同部分,在docker中只会存储一份,这是docker的空间优化机制
镜像
-
拉取一个镜像
docker pull ubuntu:20.04 # 拉取一个名称为ubuntu,版本号为20.04的镜像。镜像的格式为:名称:版本号
-
查看所有镜像
docker images
-
删除某个镜像
-
第一种方法
docker image rm ubuntu:20.04 # 删除名称为ubuntu,版本号为20.04的镜像
-
第二种方法
docker rmi ubuntu:20.04 # 删除名称为ubuntu,版本号为20.04的镜像
-
-
把某个容器制作成一个镜像
docker commit be9201155c08 cgw_temp:10.01 # 将容器ID为be9201155c08的容器制作成一个名称为cgw_temp,版本号为10.01的镜像
-
将某个镜像导出成存放于本地中的某个文件
docker save -o ubuntu_20_04.tar ubuntu:20.04 # 将名称为ubuntu,版本号为20.04的镜像,导出成存放于本地中的ubuntu_20_04.tar文件
-
从存放于本地中的某个文件中加载出一个镜像
docker load -i ubuntu_20_04.tar # 从存放于本地中的ubuntu_20_04.tar文件中加载出一个镜像
容器
-
利用某个镜像创建一个容器
docker create -it ubuntu:20.04 # 利用名称为ubuntu,版本号为20.04的镜像,创建一个容器
-
查看所有容器
docker ps -a
-
查看正在运行的容器
docker ps
-
启动某个容器
docker start a62bd026d5fb # 启动容器ID为a62bd026d5fb的容器
-
停止某个正在运行的容器
docker stop a62bd026d5fb # 停止容器ID为a62bd026d5fb的容器
-
重启某个正在运行的容器
docker restart a62bd026d5fb # 重启容器ID为a62bd026d5fb的容器
-
利用某个镜像创建并启动一个容器
docker run -itd ubuntu:20.04 # 利用名称为ubuntu,版本号为20.04的镜像,创建并启动一个容器
-
进入正在运行的某个容器
docker attach be9201155c08 # 进入正在运行的容器ID为be9201155c08的容器
键盘按下CTRL + p,然后键盘按下CTRL + q,退出并挂起当前容器
键盘按下CTRL + d,退出并停止当前容器
-
在正在运行的某个容器中执行命令
docker exec be9201155c08 ls -l # 在正在运行的容器ID为be9201155c08的容器中执行ls -l命令
-
删除已停止的某个容器
docker rm a62bd026d5fb # 删除已停止的容器ID为a62bd026d5fb的容器
-
删除所有已停止的容器
docker container prune
-
将已停止的某个容器导出成存放于本地中的某个文件
docker export -o temp.tar 14185706f3fd # 将已停止的容器ID为14185706f3fd的容器导出成存放于本地中的temp.tar文件
-
从存放于本地中的某个文件中加载出一个容器模板镜像,并将容器模板镜像命名为:名称:版本号
docker import temp.tar yxchhh:10.07 # 从存放于本地中的temp.tar文件中加载出一个容器模板镜像,并将容器模板镜像命名为:yxchhh:10.07
-
注意,docker save/load与docker export/import的区别
- docker save/load:会保存完整记录,体积更大
- docker export/import:会丢弃历史记录和元数据信息,仅保存容器当时的快照状态
-
查看正在运行的某个容器内的所有进程
docker top be9201155c08 # 查看正在运行的容器ID为be9201155c08的容器内的所有进程
-
查看所有容器的统计信息,包括CPU、内存、硬盘空间、网络等信息
docker stats
键盘按下CTRL + c,即可退出
-
在本地和某个正在运行的容器间复制文件
-
把存放于本地中的某个文件复制到正在运行的某个容器中
docker cp temp.tar be9201155c08:/root/ # 把存放于本地中的temp.tar文件复制到正在运行的容器ID为be9201155c08的容器中的/root/路径下
-
把存放于正在运行的某个容器中的某个文件复制到本地中
docker cp be9201155c08:/root/ . # 把存放于正在运行的容器ID为be9201155c08的容器中的/root目录复制到本地中,这里复制目录时,不需要加-r
-
-
将某个容器重命名
docker rename be9201155c08 yxc_lesson # 将容器ID为be9201155c08的容器重命名
-
修改某个容器的内存、CPU等限制
docker update be9201155c08 --memory 500MB # 将容器ID为be9201155c08的容器的内存上限改为500MB
通过ssh登录某个正在运行的容器
前提:在腾讯云云服务器上,已经存在一个名称为docker_lesson,版本号为1.0的镜像
-
利用名称为docker_lesson,版本号为1.0的镜像,创建并启动一个容器,并且把容器内的22端口映射到本地(即自己租的腾讯云云服务器)的20000端口,容器名称改成my_docker_server
docker run -p 20000:22 --name my_docker_server -itd docker_lesson:1.0
-
进入正在运行的容器名称为my_docker_server的容器
docker attach my_docker_server
-
进入正在运行的容器名称为my_docker_server的容器后,执行如下命令,可以给容器名称为my_docker_server的容器的root用户设置一个密码,密码和本地(云服务器)acs用户的密码一样
passwd
-
键盘按下CTRL + p,然后键盘按下CTRL + q,退出并挂起当前容器
-
在腾讯云官网上,给自己租的腾讯云云服务器开放20000端口
-
进入正在运行的容器名称为my_docker_server的容器后,创建acs用户,并且授予acs用户sudo权限
adduser acs # 创建acs用户,密码和本地(云服务器)acs用户的密码一样 usermod -aG sudo acs # 给acs用户分配sudo权限
-
在正在运行的容器名称为my_docker_server的容器上,切换到acs用户,验证一下是否创建acs用户成功
su acs
-
键盘按下CTRL + p,然后键盘按下CTRL + q,退出并挂起当前容器
-
在AC Terminal上,配置免密登录方式,登录云服务器的正在运行的容器名称为my_docker_server的容器(直接进入acs用户),详细操作可以参考《ssh》这一章节中的知识点,这里就不再过多的赘述
-
接下来,可以在正在运行的容器名称为my_docker_server的容器上,安装tmux,安装docker等等。也可以在AC Terminal上,将AC Terminal的配置传到腾讯云云服务器的正在运行的容器名称为my_docker_server的容器上,可以让腾讯云云服务器的正在运行的容器名称为my_docker_server的容器的基本使用环境和AC Terminal一致
修改软件源
如果通过apt-get下载软件的速度较慢,可以参考清华大学开源软件镜像站(ubuntu | 镜像站使用帮助 | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror)中的内容,修改软件源
补充内容
.vimrc
acs@80826ae841a9:~$ cat .vimrc
" An example for a vimrc file.
"
" To use it, copy it to
" for Unix and OS/2: ~/.vimrc
" for Amiga: s:.vimrc
" for MS-DOS and Win32: $VIM\_vimrc
" for OpenVMS: sys$login:.vimrc
" When started as "evim", evim.vim will already have done these settings.
if v:progname =~? "evim"
finish
endif
" Use Vim settings, rather then Vi settings (much better!).
" This must be first, because it changes other options as a side effect.
set nocompatible
" allow backspacing over everything in insert mode
set backspace=indent,eol,start
if has("vms")
set nobackup " do not keep a backup file, use versions instead
else
set backup " keep a backup file
endif
set history=50 " keep 50 lines of command line history
set ruler " show the cursor position all the time
set showcmd " display incomplete commands
set incsearch " do incremental searching
"==========================================================================
"My Setting-sunshanlu
"==========================================================================
vmap <leader>y :w! /tmp/vitmp<CR>
nmap <leader>p :r! cat /tmp/vitmp<CR>
"语法高亮
syntax enable
syntax on
"显示行号
set nu
"修改默认注释颜色
"hi Comment ctermfg=DarkCyan
"允许退格键删除
"set backspace=2
"启用鼠标
set mouse=a
set selection=exclusive
set selectmode=mouse,key
"按C语言格式缩进
set cindent
set autoindent
set smartindent
set shiftwidth=4
" 允许在有未保存的修改时切换缓冲区
"set hidden
" 设置无备份文件
set writebackup
set nobackup
"显示括号匹配
set showmatch
"括号匹配显示时间为1(单位是十分之一秒)
set matchtime=5
"显示当前的行号列号:
set ruler
"在状态栏显示正在输入的命令
set showcmd
set foldmethod=syntax
"默认情况下不折叠
set foldlevel=100
" 开启状态栏信息
set laststatus=2
" 命令行的高度,默认为1,这里设为2
set cmdheight=2
" 显示Tab符,使用一高亮竖线代替
set list
"set listchars=tab:\|\ ,
set listchars=tab:>-,trail:-
"侦测文件类型
filetype on
"载入文件类型插件
filetype plugin on
"为特定文件类型载入相关缩进文件
filetype indent on
" 启用自动补全
filetype plugin indent on
"设置编码自动识别, 中文引号显示
filetype on "打开文件类型检测
"set fileencodings=euc-cn,ucs-bom,utf-8,cp936,gb2312,gb18030,gbk,big5,euc-jp,euc-kr,latin1
set fileencodings=utf-8,gb2312,gbk,gb18030
"这个用能很给劲,不管encoding是什么编码,都能将文本显示汉字
"set termencoding=gb2312
set termencoding=utf-8
"新建文件使用的编码
set fileencoding=utf-8
"set fileencoding=gb2312
"用于显示的编码,仅仅是显示
set encoding=utf-8
"set encoding=utf-8
"set encoding=euc-cn
"set encoding=gbk
"set encoding=gb2312
"set ambiwidth=double
set fileformat=unix
"设置高亮搜索
set hlsearch
"在搜索时,输入的词句的逐字符高亮
set incsearch
" 着色模式
set t_Co=256
"colorscheme wombat256mod
"colorscheme gardener
"colorscheme elflord
colorscheme desert
"colorscheme evening
"colorscheme darkblue
"colorscheme torte
"colorscheme default
" 字体 && 字号
set guifont=Monaco:h10
"set guifont=Consolas:h10
" :LoadTemplate 根据文件后缀自动加载模板
"let g:template_path='/home/ruchee/.vim/template/'
" :AuthorInfoDetect 自动添加作者、时间等信息,本质是NERD_commenter && authorinfo的结合
""let g:vimrc_author='sunshanlu'
""let g:vimrc_email='sunshanlu@baidu.com'
""let g:vimrc_homepage='http://www.sunshanlu.com'
"
"
" Ctrl + E 一步加载语法模板和作者、时间信息
""map <c-e> <ESC>:AuthorInfoDetect<CR><ESC>Gi
""imap <c-e> <ESC>:AuthorInfoDetect<CR><ESC>Gi
""vmap <c-e> <ESC>:AuthorInfoDetect<CR><ESC>Gi
" ======= 引号 && 括号自动匹配 ======= "
"
":inoremap ( ()<ESC>i
":inoremap ) <c-r>=ClosePair(')')<CR>
"
":inoremap { {}<ESC>i
"
":inoremap } <c-r>=ClosePair('}')<CR>
"
":inoremap [ []<ESC>i
"
":inoremap ] <c-r>=ClosePair(']')<CR>
"
":inoremap < <><ESC>i
"
":inoremap > <c-r>=ClosePair('>')<CR>
"
"":inoremap " ""<ESC>i
"
":inoremap ' ''<ESC>i
"
":inoremap ` ``<ESC>i
"
":inoremap * **<ESC>i
" 每行超过80个的字符用下划线标示
""au BufRead,BufNewFile *.s,*.asm,*.h,*.c,*.cpp,*.java,*.cs,*.lisp,*.el,*.erl,*.tex,*.sh,*.lua,*.pl,*.php,*.tpl,*.py,*.rb,*.erb,*.vim,*.js,*.jade,*.coffee,*.css,*.xml,*.html,*.shtml,*.xhtml Underlined /.\%81v/
"
"
" For Win32 GUI: remove 't' flag from 'guioptions': no tearoff menu entries
" let &guioptions = substitute(&guioptions, "t", "", "g")
" Don't use Ex mode, use Q for formatting
map Q gq
" This is an alternative that also works in block mode, but the deleted
" text is lost and it only works for putting the current register.
"vnoremap p "_dp
" Switch syntax highlighting on, when the terminal has colors
" Also switch on highlighting the last used search pattern.
if &t_Co > 2 || has("gui_running")
syntax on
set hlsearch
endif
" Only do this part when compiled with support for autocommands.
if has("autocmd")
" Enable file type detection.
" Use the default filetype settings, so that mail gets 'tw' set to 72,
" 'cindent' is on in C files, etc.
" Also load indent files, to automatically do language-dependent indenting.
filetype plugin indent on
" Put these in an autocmd group, so that we can delete them easily.
augroup vimrcEx
au!
" For all text files set 'textwidth' to 80 characters.
autocmd FileType text setlocal textwidth=80
" When editing a file, always jump to the last known cursor position.
" Don't do it when the position is invalid or when inside an event handler
" (happens when dropping a file on gvim).
autocmd BufReadPost *
\ if line("'\"") > 0 && line("'\"") <= line("$") |
\ exe "normal g`\"" |
\ endif
augroup END
else
set autoindent " always set autoindenting on
endif " has("autocmd")
" 增加鼠标行高亮
set cursorline
hi CursorLine cterm=NONE ctermbg=darkred ctermfg=white
" 设置tab是四个空格
set ts=4
set expandtab
" 主要给Tlist使用
let Tlist_Exit_OnlyWindow = 1
let Tlist_Auto_Open = 1
acs@80826ae841a9:~$
.tmux.conf
acs@80826ae841a9:~$ cat .tmux.conf
set-option -g status-keys vi
setw -g mode-keys vi
setw -g monitor-activity on
# setw -g c0-change-trigger 10
# setw -g c0-change-interval 100
# setw -g c0-change-interval 50
# setw -g c0-change-trigger 75
set-window-option -g automatic-rename on
set-option -g set-titles on
set -g history-limit 100000
#set-window-option -g utf8 on
# set command prefix
set-option -g prefix C-a
unbind-key C-b
bind-key C-a send-prefix
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R
bind -n M-Left select-pane -L
bind -n M-Right select-pane -R
bind -n M-Up select-pane -U
bind -n M-Down select-pane -D
bind < resize-pane -L 7
bind > resize-pane -R 7
bind - resize-pane -D 7
bind + resize-pane -U 7
bind-key -n M-l next-window
bind-key -n M-h previous-window
set -g status-interval 1
# status bar
set -g status-bg black
set -g status-fg blue
#set -g status-utf8 on
set -g status-justify centre
set -g status-bg default
set -g status-left " #[fg=green]#S@#H #[default]"
set -g status-left-length 20
# mouse support
# for tmux 2.1
# set -g mouse-utf8 on
set -g mouse on
#
# for previous version
#set -g mode-mouse on
#set -g mouse-resize-pane on
#set -g mouse-select-pane on
#set -g mouse-select-window on
#set -g status-right-length 25
set -g status-right "#[fg=green]%H:%M:%S #[fg=magenta]%a %m-%d #[default]"
# fix for tmux 1.9
bind '"' split-window -vc "#{pane_current_path}"
bind '%' split-window -hc "#{pane_current_path}"
bind 'c' new-window -c "#{pane_current_path}"
# run-shell "powerline-daemon -q"
# vim: ft=conf
acs@80826ae841a9:~$
.bashrc
acs@80826ae841a9:~$ cat .bashrc
# ~/.bashrc: executed by bash(1) for non-login shells.
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
# for examples
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac
# don't put duplicate lines or lines starting with space in the history.
# See bash(1) for more options
HISTCONTROL=ignoreboth
# append to the history file, don't overwrite it
shopt -s histappend
# for setting history length see HISTSIZE and HISTFILESIZE in bash(1)
HISTSIZE=1000
HISTFILESIZE=2000
# check the window size after each command and, if necessary,
# update the values of LINES and COLUMNS.
shopt -s checkwinsize
# If set, the pattern "**" used in a pathname expansion context will
# match all files and zero or more directories and subdirectories.
#shopt -s globstar
# make less more friendly for non-text input files, see lesspipe(1)
[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)"
# set variable identifying the chroot you work in (used in the prompt below)
if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then
debian_chroot=$(cat /etc/debian_chroot)
fi
# set a fancy prompt (non-color, unless we know we "want" color)
case "$TERM" in
xterm-color|*-256color) color_prompt=yes;;
esac
# uncomment for a colored prompt, if the terminal has the capability; turned
# off by default to not distract the user: the focus in a terminal window
# should be on the output of commands, not on the prompt
#force_color_prompt=yes
if [ -n "$force_color_prompt" ]; then
if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then
# We have color support; assume it's compliant with Ecma-48
# (ISO/IEC-6429). (Lack of such support is extremely rare, and such
# a case would tend to support setf rather than setaf.)
color_prompt=yes
else
color_prompt=
fi
fi
if [ "$color_prompt" = yes ]; then
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
else
PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
fi
unset color_prompt force_color_prompt
# If this is an xterm set the title to user@host:dir
case "$TERM" in
xterm*|rxvt*)
PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1"
;;
*)
;;
esac
# enable color support of ls and also add handy aliases
if [ -x /usr/bin/dircolors ]; then
test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
alias ls='ls --color=auto'
#alias dir='dir --color=auto'
#alias vdir='vdir --color=auto'
alias grep='grep --color=auto'
alias fgrep='fgrep --color=auto'
alias egrep='egrep --color=auto'
fi
# colored GCC warnings and errors
#export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01'
# some more ls aliases
alias ll='ls -alF'
alias la='ls -A'
alias l='ls -CF'
# Add an "alert" alias for long running commands. Use like so:
# sleep 10; alert
alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"'
# Alias definitions.
# You may want to put all your additions into a separate file like
# ~/.bash_aliases, instead of adding them here directly.
# See /usr/share/doc/bash-doc/examples in the bash-doc package.
if [ -f ~/.bash_aliases ]; then
. ~/.bash_aliases
fi
# enable programmable completion features (you don't need to enable
# this, if it's already enabled in /etc/bash.bashrc and /etc/profile
# sources /etc/bash.bashrc).
if ! shopt -oq posix; then
if [ -f /usr/share/bash-completion/bash_completion ]; then
. /usr/share/bash-completion/bash_completion
elif [ -f /etc/bash_completion ]; then
. /etc/bash_completion
fi
fi
export PATH=/home/acs/.homework:$PATH
alias tmux='tmux -u'
export PATH=/home/acs/homework/lesson_7/homework_0:$PATH
acs@80826ae841a9:~$