Qeuroal's Blog

静幽正治

说明

  • :command: 命令
  • keyword: 快捷键

帮助

使用内置帮助(built-in help)

使用 vim 的内置帮助是一个好习惯(虽然很多朋友更喜欢在网上搜索相关的使用方法)。查看帮助的语法如下表格所示:

**前缀 ** **例子 ** **说明 **
: :help :w 有关 :w 命令的帮助
none :help j 有关“j”键在正常模式上下文中的帮助
v_ :help v_J 有关在上下文中使用“J”键到视觉模式的帮助
i_ :help i_<Esc> 有关在上下文中使用“Esc”键插入模式的帮助
/ :help /\n 有关搜索模式“\n”的帮助

make

命令 说明
:make 内置命令编译项目
:cl 显示编译错误信息
:cc + 数字 跳转编译错误位置
:cp/:cn 向前/向后导航
copen 打开 quickfix 窗口来查看编译信息

快捷键

命令行上移动光标时最常用的键

命令行上移动光标时最常用的键: C: ctrl; S: shift

命令 说明
<Left> 左移一个字符
<Right> 右移一个字符
<S-Left><C-Left> 左移一个单词
<S-Right> <C-Right> 右移一个单词
<C-B><Home> 命令行行首
<C-E><End> 命令行行尾
<C-W> 删除光标前整个单词
<C-U> 删除命令行上全部文字,从而让你从头开始。

注意

<S-Left> (光标左移键和 Shift 键同时按下) 和 <C-Left> (光标左移键和 Control 键同时按下) 并非在所有键盘上都有效。其它 ShiftControl 组合键也是这种情况。

编辑

刷新文件

命令

在 vim 打开一个文件,在另一个地方修改了文件

  • :e重新加载文件
  • :e!强制丢掉本地修改,从磁盘加载文件

配置自动刷新

vim提供了自动加载的选项 autoread,默认关闭。

1
:set autoread

在vimrc中添加 set autoread即可打开自动加载选项,相关选项:

  • :help 'autoread'
  • :help timestamp
  • :help FileChangedShell
  • :help :checktime

另外,vim使用tag进行切换时,如果当前文件修改未保存,会提示需保存后才能跳转。
在vimrc中添加

1
set autowriteall

可使切换文件时,修改的文件被自动保存。

撤销

关闭文件再重新打开时,无法撤回历史动作。以下配置可以实现持久化undo记录

1
2
3
set undofile 
" 配置你的undo保存路径
set undodir=~/.vim/undodir

十六进制

二进制打开文件

1
vim -b datafile

vim 的 -b 选项是告诉vim打开的是一个二进制文件,不指定的话,会在后面加上 0x0a ,即一个换行符

十六进制查看

1
:%!xxd

返回正常的格式:

1
:%!xxd -r

分组:

命令 说明
:%!xxd -g 1 表示每1个字节为1组
:%!xxd -g 2 表示每2个字节为1组(默认)
:%!xxd -g 4 表示每4个字节为1组
man xxd 获得xxd的帮助文件

无权限保存

在编辑系统文件或者受权限保护的文件的时候,很容易会忘记在 vim 编辑之前添加 sudo,这样将会以只读模式打开文件,也就是编辑后不能保存。

但是这时候,你可能已经对文件做了一些修改(尚未保存),很显然,强制退出不是一个好选择。

非文件所有者保存时提示没有权限,为了避免丢失原有的改动,可以使用以下命令。其中实现原理也很简单,可以参考这里

1
:w !sudo tee %

键入此命令后,将要求您输入sudo命令的密码,然后文件就可以保存了。

注:我们应该使用 sudoedit 命令而不是 sudo vim 来编辑需要超级用户权限的文件。

我们将上述命令拆解来看下:

命令 说明
:w 这是写入命令。由于没有给出参数,vim 将把整个文件写入标准输出;
!sudo 将 sudo 命令作为 shell 命令而不是 vim 命令运行;
tee tee命令用于读取标准输入并将其写入标准输出或文件;
% vim 将其替换为您正在编辑的当前文件的名称。

:w 命令将整个文件写入 STDOUT(标准输出);然后,我们使用sudo命令(因为我们编辑的毕竟是一个系统文件)来获得临时权限。

百分号(%)表示文件名,tee 命令从 STDOUT 获取 vim 的输出并将其写入 % 文件。

这基本上适用于 <Vim's STDOUT> | sudo tee /etc/ssh/sshd_config,有点复杂…

缩进

快捷键

快捷键 说明
>> 向右给它进当前行
<< 向左缩进当前行
= 缩进当前行 (和上面不一样的是,它会对齐缩进)
=% 把光标位置移到语句块的括号上,然后按=%,缩进整个语句块(%是括号匹配)
G=gggg=G 缩进整个文件(G是到文件结尾,gg是到文件开头)

粘贴代码保留缩进

我们都有过在互联网上复制代码的时候。当将代码粘贴到文件中时,缩进都给弄乱了,这时候需要怎样做呢?

为了避免这种情况,请在 .vimrc 文件中添加以下代码:

1
set pastetoggle=<F2>

对 vimrc 文件进行如上更改后,在粘贴代码之前按 F2 键,这样做将确保代码粘贴正确的缩进。

以正确的缩进深度开始书写

假设光标在第一行第一列,但是所要写的内容需要缩进,那在不按下制表符(tab)和空格键的情况下,应该怎样做呢?

答案是在正常模式下按下 S 键。

当光标位于行的第一列时,按 Esc 键进入正常模式。然后按 S(大写)键,这会将光标移动到适当的缩进深度,并自动进入“插入”模式,以便开始键入。

光标移动

快捷键 说明
Ctrl + O 向后回退你的光标移动
Ctrl + I 向前追赶你的光标移动
Ctrl + ^ 跳转至先前编辑过的buffer

保存文件前显示差异

我们可能遇到过这样的情况:我修改了这个文件,但是忘记都做了哪些修改了,并且我担心其中有些地方可能修改错了。

解决此问题的方法是查看缓冲区和文件之间的差异。可在 vim 中执行如下命令:

1
:w !diff % -

我们将上述命令拆解来看:

命令 说明
:w 用于保存/写入,在这个特定场景中,如果命令中没有指定文件名,则输出将写入STDIN(标准输入)文件;
:!<command> 是执行 shell 命令的语法,在这个例子中,我们在 shell 中运行 diff 命令;
% 表示未修改的当前文件的名称;试试这个::!echo %
- 是 diff 命令的 STDIN 文件。

因此,该命令首先将所有[未保存]内容写入STDIN文件。然后diff命令读取当前文件(%)并将其与STDIN(-)文件进行比较。

这个命令大致等同于这个shell命令:diff <original-file> <Vim's STDOUT>

显示拼写错误

我们应该都使用过 Microsoft word,其拼写检查器在拼写错误的单词下会有一条红色的波浪线。

vim 也内置了拼写检查器,但默认情况下是关闭的。我们可以使用如下命令启用它:

1
:set spell

这样,你可能会看到拼写错误的单词被突出显示,其突出显示的方式取决于你的 vim 颜色方案。我在拼写错误的单词下面有一条白色下划线,如下图所示:

要将这设置为 vim 的默认,可在 .vimrc 文件中添加如下配置:

1
set spell

使用 vim 打开文件的同时将光标定位在某一行

默认情况下,我们使用 vim 打开文件,光标总会在第一行。在某些时候,我们希望光标能够定位在我们指定的某一行,而不是第一行。

可以通过使用 +n(n为行号)选项来实现这一点,当然前提是你需要知道打开的文件总行数应大于或等于 n,如下:

1
vim +n <file-name>

在插入模式下删除文本

我们都知道,在正常模式(normal mode)下,可以使用 dx 键删除文本,那么在插入模式下如何执行相同的操作(比如 dd)呢?

以下是常用的一些方案:

快捷键 说明
ctrl + w 删除前一个单词(字)(相当于正常模式下的 db
ctrl + h 删除前一个字符
ctrl + u 删除当前行所有前面的字符(相当于正常模式下的 d0
ctrl + k 删除当前行中所有主要字符(相当于正常模式下的 d$

重新加载.vimrc 文件

输入下面任一命令重载 ~/.vimrc:so $MYVIMRC 或者 :source ~/.vimrc

:so[urce]! {file} 这个 vim 命令会从给定的文件比如 ~/.vimrc 读取配置。就像你输入的一样,这些命令是在普通模式下执行的。当你在 :global、:argdo:windo:bufdo 之后、循环中或者跟着另一个命令时,显示不会再在执行命令时更新。

分屏与标签页

分屏

命令 说明
:He[xplore] 把当前窗口上下分屏,并在下面进行目录浏览. (在下边分屏浏览目录)
:He[xplore]! 把当前窗口上下分屏,并在上面进行目录浏览. (在上边分屏浏览目录)
:Ve[xplore] 左右分屏(在左边分屏间浏览目录)
:Ve[xplore]! 左右分屏(在右边分屏间浏览目录)

分屏同步移动

命令 说明
:set scb 让两个分屏中的文件同步移动, 要到需要同步移动的两个屏中都输入如下命令
(相当于使用“铁锁连环”)
:set scb! 需要解开,那么就输入下面的命令

注:set scbset scrollbind 的简写

分页

命令 说明
:Te[xplorer] 像Chrome这样的分页式的浏览
gt 到下一个页
gT 到前一个页
{i}gt i是数字,到指定页,比如:5 gt就是到第5页
:tabm {n} 切换Tab页
:tabs 查看现在打开的窗口和Tab的情况
:tabclose [i] 如果后面指定了数字,那就关闭指定页,如果没有就关闭当前页
vim -p <files> 如果你在Shell命令行下,你可以使用 vim 的 -p 参数来用Tab页的方式打开多个文件,
如: vim -p *.cpp
:bufdo tab split 把buffer中的文件全转成Tab页

分屏方式

  • :split 缩写 :sp or Ctrl-w s 上下分屏
  • :vsplit 缩写 :vs or Ctrl-w v 左右分屏
  • :diffsplit 缩写 :diffs diff 模式打开一个分屏,后面可以加上 {filename}

窗口跳转

  • Ctrl-w w 激活下一个窗口
  • Ctrl-w j 激活下方窗口
  • Ctrl-w k 激活上方窗口
  • Ctrl-w h 激活左侧窗口
  • Ctrl-w l 激活右侧窗口

移动分屏

  • Ctrl-w L 移动到最右侧
  • Ctrl-w H 移动到最左侧
  • Ctrl-w K 移动到顶部
  • Ctrl-w J 移动到底部

注意:区分大小写。另外,可以将底部的屏幕移动到右侧,实现上下分屏到左右分屏的转换。

屏幕缩放

  • Ctrl-w = 平均窗口尺寸
  • Ctrl-w + 增加高度
  • Ctrl-w - 缩减高度
  • Ctrl-w _ 最大高度
  • Ctrl-w > 增加宽度
  • Ctrl-w < 缩减宽度
  • Ctrl-w | 最大宽度

缓冲区

命令/快捷键 说明
:ls or :buffers 查看缓冲区
:b[uffer] <n>
:b[uffer] <filename>
打开缓冲区n/<filename>
:bn[ext] 切换到下一个缓冲区
:bp[revious] 切换到上一个缓冲区
:bl[ast] 切换到最后一个缓冲区
:bf[irst] 切换到最前一个缓冲区

buffer 标记说明

标记 说明
(非活动的缓冲区)
a (当前被激活缓冲区)
h (隐藏的缓冲区)
% (当前的缓冲区)
# (交换缓冲区)
= (只读缓冲区)
+ (已经更改的缓冲区)

Quickfix

命令 说明
:cope[n] 打开quickfix
:cw[indow] 如果有错误, 则打开quickfix; 如果没有错误且quickfix开启, 则关闭quickfix
:cp 跳到上一个错误
:cn 跳到下一个错误
:cl 列出所有错误
:cc 显示错误详细信息

字符相关

字符改变

快捷键 说明
guu或是 Vu 把一行的文字变成全小写
gUU 或是 VU 把一行的文件变成全大写
v 进入选择模式,然后移动光标选择你要的文本,
u转小写,按U转大写
ga 查看光标处字符的ascii码
g8 查看光标处字符的utf-8编码
gf 打开光标处所指的文件
(这个命令在打到#include头文件时挺好用的,当然,仅限于有路径的)
*# 在当前文件中搜索当前光标的单词

显示隐藏的特殊字符

你是否在 Python、YAML等要求严格缩进格式的文件中遇到过问题?检查之后,发现文档的内容都是正确的,除了缩进,因为其中有一行是缩进了3个空格,而不是4个空格。

这种情况经常发生。大多数IDE允许我们查看特殊字符,并能识别行尾、空格和制表符。vim 不亚于其他任何IDE,它也可以显示那些隐藏的字符。

Vim中的隐藏字符

vim 中的隐藏字符可以被认为是“空格”。以下是 vim 为了更好的易读性而隐藏的字符:

字符 含义
eol 行尾(end of line)
tab
trail 换行符前的空格
extends 最后一列中的字符,表示下一行是换行的延续
precedes 第一列中的字符,表示此行是前一行的延续
conceal
nbsp 空格字符

显示隐藏字符

要临时显示隐藏字符,可使用如下命令:

1
:set list

临时显示隐藏字符后,如果想再次将隐藏字符隐藏,可使用如下命令:

1
:set nolist

如上图所示,启用 list 选项来显示隐藏字符后,文本区域会看到有 $ 字符,表示换行符。

永久 显示换行符,可将如下命令添加到 vimrc 文件中:

1
set list

更改隐藏字符

当打开隐藏字符的可见性时,vim有一个预先定义的字符集合,如上图所示,换行符由美元符号 $ 表示。

但是如果你不想要美元符号呢?如果你想要一个不同的字符来表示换行符呢?

以下是设置隐藏字符的一个例子:

1
:set listchars=eol:^,tab:-,trail:!,extends:>,precedes:<

上面的例子中,设置显示行尾(eol)的字符在 eol: 后面键入即可。

如上图所示,我复制了空格并将其粘贴在行尾,它们显示为感叹号 !,同时,行尾字符由 $ 变为了 ^

如果要永久使用上述设置,可将下面的命令添加到 vimrc 文件中:

1
set listchars=eol:^,tab:-,trail:!,extends:>,precedes:<

将所有空格转为制表符(或者反过来)

我们都喜欢使用制表符(tab)或者空格,但是,如果我们正在编辑的文本其缩进使用的符号正好与我们的习惯相反,该怎么办?

将所有空格转换为制表符

如果当前文件使用空格缩进文本,希望将它们转换为制表符时,需要运行如下两个 vim 命令:

1
2
:set noexpandtab
:retab!

这样做会将所有空格转换为其等效的制表符。如果文档使用两个空格作为缩进宽度,它们将转换为1个制表符。如果 4 个空格用作单个缩进宽度时,这 4 个制表位将替换为 1 个制表字符。

将所有制表符转换为空格

如果要编辑的文件使用制表符缩进,并且要将制表符转换为空格,则需要运行如下4个 vim 命令:

1
2
3
4
:set expandtab
:set tabstop=4
:set shiftwidth=4
:retab

第一个命令(expandtab)告诉 vim 使用空格展开 tab,第二个命令(tabstop)设置使用多少个空格用作一个“缩进块”。

在我们的例子中,我们定义了“1个tab=4个空格”;当使用>>运算符时,shiftwidth 命令用于控制缩进,这也被设置为4个空格。

最后,retab 命令将所有制表符(用于缩进)转换为空格。

正则表达式

先来看一个现实的问题,如果在 Vim 中,将正则表达式中定义的大量元字符原封不动地引用(就像 perl),势必会给使用正常编辑功能的人造成困扰。比如 /foo(1) 命令,按照正则表达式来理解会是搜索 foo1 字符串。而在大多数人编辑器中应该是搜索 foo(1) 字符串。

Vim 毕竟是一个编辑器,于是在 Vim 中规定,正则表达式的元字符必须用反斜杠进行转义(和大多数正则表达式对转义符的定义正好相反)。如果上面的例子要用正则表达式搜索,就应写成 /foo\(1\) 。但是,像 . * 这种极其常用的元字符,都加上反斜杠就太麻烦了。而且,众口难调,有些人喜欢用正则表达式,有些人不喜欢用…

为了解决这个问题,Vim 设置了 magic 变量。简单地说,magic 就是设置哪些元字符要加反斜杠哪些不用加的。 简单来说:

  • magic (\m):除了 $ . * ^ 之外其他元字符都要加反斜杠
  • nomagic (\M):除了 $ ^ 之外其他元字符都要加反斜杠

这个设置也可以在正则表达式中通过 \m \M 开关临时切换。 \m 后面的正则表达式会按照 magic 处理, \M 后面的正则表达式按照 nomagic 处理,并忽略实际的 magic 设置。

例如:

1
2
/\m.*   # 查找任意字符串
/\M.* # 查找字符串 .* (点号后面跟个星号)

另外还有两个包含全部的命令。

  • \v (即 very magic):任何元字符都不用加反斜杠
  • \V (即 very nomagic):任何元字符都必须加反斜杠

例如:

1
2
3
4
/\v(a.c){3}$      # 查找行尾的 abcaccadc
/\m(a.c){3}$ # 查找行尾的 (abc){3}
/\M(a.c){3}$ # 查找行尾的 (a.c){3}
/\V(a.c){3}$ # 查找任意位置的 (a.c){3}$

Vim 默认设置是 magic,也推荐大家都使用 magic 的设置。有特殊需求时,直接通过 \v \m \M \V 中的一种定义即可。

Vim 中设定 magic 变量:

1
2
3
:set magic     " 设置magic
:set nomagic " 取消magic
:h magic " 查看帮助

基本元素

本文下面使用的字符都是默认(magic)模式下的,在其他模式下请自行转义。

常用的元字符

元字符 意义
. 匹配任意一个字符
[abc] 匹配方括号中的任意一个字符。也可以用 - 表示范围
[a-z0-9] 匹配小写字母和阿拉伯数字中的一个字符
[^abc] 匹配除方括号中字符之外的任意一个字符
\(abc\) 分组匹配,将 abc 放入 1
\d 匹配阿拉伯数字,等同于 [0-9]
\D 匹配阿拉伯数字之外的任意字符,等同于 [^0-9]
\x 匹配十六进制数字,等同于 [0-9A-Fa-f]
\w 匹配单词字母,等同于 [0-9A-Za-z_]
\W 匹配除单词字母之外的任意字符,等同于 [^0-9A-Za-z_]
\t 匹配 <TAB> 字符
\s 匹配空白字符,等同于 [ \t]
\S 匹配非空白字符,等同于 [^ \t]
\a 匹配所有的字母字符。等同于 [a-zA-Z]
\l 匹配小写字母 [a-z]
\L 匹配非小写字母 [^a-z]
\u 匹配大写字母 [A-Z]
\U 匹配非大写字幕 [^A-Z]

注解

\(\) 进行分组匹配,在分组后面可以使用 \1\2 等变量来访问分组的内容(注意:\0 表示匹配的所有内容),最多保存一行中的 9 个分组。这种形式实际上是将分组中的内容保存到特殊的空间(保留缓冲区)中。

1
2
3
4
# 原字符串 That or this
# 替换后的字符串 this or That

:%s/\(That\) or \(this\)/\2 or \1/

量词

元字符 意义
* 匹配 0 个或多个
\+ 匹配1个或多个(匹配优先)
\?\= 0 个或 1 个,\? 不能在 ? 命令中使用
\{n,m} 匹配 n 个到 m 个
\{n,} 匹配最少 n 个
\{,m} 匹配最多 m 个
\{n} 匹配 n 个

注解

用于限定数量的元字符不仅可用于字符,也可以用于分组等模式。举例如下:

1
\(123\)\{2}   # 匹配 123123

表示位置的符号

元字符 意义
$ 匹配行尾,如 tail$ 只匹配位于一行结尾处的 tail
^ 匹配行首,如 ^head 只匹配位于一行开头处的 head
\< 匹配以某些字符开头的单词,\<ac 只匹配以 ac 开头的单词,如 action
\> 匹配以某些字符结尾的单词,ad\> 只匹配以 ac 开头的单词,如 head

非贪婪匹配

正则表达式中有贪婪匹配和非贪婪匹配两种,Vim 默认开启贪婪匹配。如果想使用非贪婪匹配,可以使用 \{-} 代替 *+ 等量词。

1
2
3
4
字符串:ahdbjkbkls

a.*b # 匹配 ahdbjkb
a.\{-}b # 匹配 ahdb

常用的一些匹配命令

  • 替换markdown文件中代码块的代码语言

    1
    :'<,'>s/^```\s*\(\n^\S\+\)/```bash\1/g
  • 将蛇形风格转化为小驼峰

    1. %s!\(\<\|_\)\([a-z]\)!\U\2!g

路径和工作目录

路径

path设置的目的是为了查找文件,比如说你使用gf指令打不开文件时,就得看看path是否设置正确了

1
2
3
4
5
6
7
8
9
10
11
12
13
:help path

//查看path
:set path?

// 检查头文件加载情况
:checkpath!

//添加path
:set path+=/sdsd/sdsd

//添加相对路径,注意要以.开头,否则无效
:set path+=./../core

默认的path包含:

  • 当前文件路径,用dot.表示
  • 当前的工作路径,用两个逗号,,表示

working directory

working directory不同于path。path表示查找文件的路径,working directory表示vim的工作路径,往往是打开vim的当前路径。在新建文件,或者打开文件时,会在working directory下操作。

working directory会被默认加到path中,即,, 用两个逗号表示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//查看working directory
:pwd


//设置工作目录
:cd %:h //跳转到当前文件目录
:lcd %:h //仅改变当前窗口的目录为当前文件目录
:cd - //跳转到前一个目录

//自动设置当前文件路径为working directory
set acd //设置自动跳转到文件路径

:help autochdir
:help :cd

DEBUG

messages

查看错误信息 当Vim出现问题时,它通常会显示一些错误信息,可以通过查看这些信息来了解问题的具体原因。在Vim中,您可以使用:messages命令来查看最近的错误和警告信息。

1
:messages

verbose

例子

有时其他 Vim 配置可能会影响 t_SI 的行为。确保没有其他设置覆盖或修改了 t_SI 的设置。您可以通过执行 :verbose set t_SI? 命令来查看最后一次设置 t_SI 的地方,并检查是否有其他配置可能会干扰它。

1
:verbose set t_SI?

详解

1
:[count]verb[ose] {command}

执行命令 {command},执行期间 ‘verbose’ 设为 [count]。 如果忽略 [count],缺省为 1。”:0verbose” 可以用来设置 ‘verbose’ 为零。

在此基础之上再应用 “:silent”,可以产生相应详细度的消息但不显示。”:silent” 和 “:verbose” 的组合因而可以只在内 部产生消息,然后用 v:statusmsg 或相关命令进行检查。
例如:

1
2
3
4
5
:let v:statusmsg = ""
:silent verbose runtime foobar.vim
:if v:statusmsg != ""
: " foobar.vim 找不到
:endif

如果和别的命令相连接,”:verbose” 只适用于第一个命令:

1
:4verbose set verbose | set verbose

verbose=4
verbose=0

要记录 verbose 消息到文件,用 ‘verbosefile’ 选项。

具体见这里

scriptname

检查Vim配置文件 如果您在Vim中添加了自定义配置,那么这些配置可能会导致一些问题。要解决这些问题,您可以尝试禁用配置并逐个重新启用来找到问题所在。您可以使用 :scriptnames 命令查看当前加载的所有脚本,并使用 :scriptname 命令检查特定的脚本。

1
:scriptname

运行环境

检查运行环境 如果您在Vim中使用外部命令或脚本,那么运行环境可能会导致一些问题。例如,某些命令或脚本可能需要特定的环境变量或依赖项。您可以使用 :! echo $PATH 命令查看当前环境变量,并使用:! 命令执行外部命令。

重定向

  1. 进入普通模式(按下 Esc 键)。
  2. 输入 :redir > filename 命令,其中 filename 是您要保存输出的文件名。
  3. 执行您的命令。
  4. 输入 :redir END 来停止重定向。
  5. 保存文件并退出 Vim。

参考

后台运行

Linux 命令是使用终端与系统交互的好方法。但是,有时可能需要一段时间才能完成手头的任务。这迫使用户等待相当长的时间或完全生成一个新的 shell。

幸运的是,您可以通过一些简单的方法在后台运行 Linux 命令。

&

在你的命令后添加一个 &

运行 Linux 后台命令的最简单方法是在命令后添加与号 (&)。例如,如果从终端启动 gedit 文本编辑器,则在关闭编辑器之前无法使用 shell。但是,当您在命令中添加额外的 & 时,您将能够立即使用 shell。

1
$ gedit &

对于需要长时间执行的任务,&符号可以使当前终端窗口不被占用,这样就能继续在同一个终端上工作,甚至关闭终端窗口也不会影响任务的正常执行。不过需要注意的是,如果要求这个任务输出内容到标准输出中(例如 echols),即便使用了 &,也会等待这些输出任务在前台运行完毕;当使用 &将一个进程放置到后台运行的时候,Bash 会提示这个进程的进程 ID。在 Linux 系统中运行的每一个进程都有一个唯一的进程 ID,我们可以使用进程 ID 来暂停、恢复或者终止对应的进程。

nohup

Linux 中 的nohup命令允许管理员运行不受挂断(Hang Up)信号影响的终端命令。您可以使用 nohup 在后台运行 Linux 命令。

nohup 的一个主要好处是,即使您退出 shell,您的命令也会运行。此外,它会生成执行的日志文件。在当前目录或 $HOME 中查找nohup.out。语法是:

1
nohup 命令

如: 后台运行Nmap 端口扫描

1
$ nohup sudo nmap -sS --top-ports=15 192.168.150.1/24

Q: Within zsh the command &! is a shortcut for disown, i.e. the program won’t get killed upon exiting the invoking shell.

程序退出不被杀死, 同时如果再次登录shell, 那么使用 ps -ef | grep "clash" 会显示clash 的父进程是 1, 这是因为创建的父进程被杀死, 那么由该进程创建的子进程会在父进程被杀死后, 父进程改为 1

1
nohup clash &> /dev/null &!

程序退出会被杀死的进程

1
nohup clash &> /dev/null &

fg和bg

命令由前台转后台

  1. 键入 ctrl+z 以暂停这条命令并返回客户端
  2. 键入 bg 命令让这条shell命令在后台执行
  3. 键入 disown -h 这条命令保证当终端关闭时,Shell脚本不会被杀死

更一般地

  1. ctrl+z将任务暂停,这时屏幕会打印这样一句 [1]+ Stopped ./myserver

  2. 使用 bg %1 将这个任务转入后台运行(1 是刚才暂停任务的job号,步骤1中屏幕提示方括号里面的内容,如果忘了也可以用 jobs 命令查看)

  3. 使用 disown –h %1 指定shell退出时不要发送SIGHUP给任务1(注意任务号前面有个%)

命令由后台转前台

  1. 键入 jobs 查看后台执行的命令
  2. 键入 fg %<d> 将 jobs[d] 切换到前台

disown

使用 disown 将 Linux 命令设置为后台运行

Linux 中 的disown命令可以轻松地在后台运行命令。首先,您需要使用& 运算符在后台发送任务。然后,键入disown以将其与shell分离。

1
$ gedit & disown

disown 的一个主要优点是,与 nohup 一样,当您关闭 shell 或注销时,系统不会终止您的任务。

使用 Tmux 在后台运行 Linux 命令

Tmux 是一个强大的多路复用器,它允许我们在单个窗口中运行多个终端会话。对于不熟悉它的人来说,学习 tmux 是一个很好的选择。Tmux 使在 Linux 中运行后台命令毫不费力。

1
tmux new -d 'ping -c 10 8.8.8.8 > www.itpro.net.cn.log'

当您运行上述tmux命令时,它将在单独的 shell 中执行ping命令并将其保留在后台。您可以使用此方法在后台执行任何 Linux 命令。

能够在后台运行命令使系统管理对管理员来说更有效率。您可以通过多种方式为您的任务做背景。像&和Ctrl + Z这样的 Bash 功能很方便,但系统会在 shell 关闭时终止后台作业。另一方面,即使您注销或终止 shell ,诸如nohupdisown 之类的工具也会使您的命令保持运行。

如果您将程序长时间留在后台,如果编码不当,它们可能会变成僵尸进程。这些过程会显着降低系统速度。因此,请确保每隔一段时间识别并杀死僵尸进程。

查看日志

查看日志常用命令

tail

-n 是显示行号;相当于nl命令;例子如下:

tail -100f test.log 实时监控100行日志

tail -n 10 test.log 查询日志尾部最后10行的日志;

tail -n +10 test.log 查询10行之后的所有日志;

跟tail是相反的,tail是看后多少行日志;例子如下:

head -n 10 test.log 查询日志文件中的头10行日志;

head -n -10 test.log 查询日志文件除了最后10行的其他所有日志;

cat

tac是倒序查看,是cat单词反写;例子如下:

cat -n test.log |grep "debug" 查询关键字的日志

应用场景

应用场景一

按行号查看—过滤出关键字附近的日志

  • cat -n test.log |grep "debug" 得到关键日志的行号
  • cat -n test.log |tail -n +92|head -n 20 选择关键字所在的中间一行. 然后查看这个关键字前10行和后10行的日志:
  • tail -n +92 表示查询92行之后的日志
  • head -n 20 则表示在前面的查询结果里再查前20条记录

应用场景二

根据日期查询日志

  • sed -n '/2014-12-17 16:17:20/,/2014-12-17 16:17:36/p' test.log

特别说明:上面的两个日期必须是日志中打印出来的日志,否则无效;

grep '2014-12-17 16:17:20' test.log 来确定日志中是否有该 时间点

应用场景三

日志内容特别多,打印在屏幕上不方便查看

  • 使用more和less命令,

    如: cat -n test.log |grep "debug" |more 这样就分页打印了,通过点击空格键翻页

  • 使用 >xxx.txt 将其保存到文件中,到时可以拉下这个文件分析

    如:cat -n test.log |grep "debug" >debug.txt

文件颜色所代表的含义

颜色 文件类型标识 含义
浅蓝色 [l] 软链接
白色 [-] 普通文件/硬链接
蓝色 [d] 目录
红色 [l] 某文件被删除后,链接到该文件的软链接的颜色
红色闪烁 表示该文件已被删除,但还存在该文件的软链接
红色 [-] 压缩包
黄色 [c] 字符设备文件,如键盘鼠标
绿色 [-] 可执行文件,可执行的程序
桃红色 [s] 套接字文件
土黄色 [p] 管道文件
灰色文件 表示其它文件

文件属性查看

端口占用情况

1
netstat -tunlp

用于显示 tcp,udp 的端口和进程等相关情况。

netstat 查看端口占用语法格式:

1
netstat -tunlp | grep 端口号
  • -t (tcp) 仅显示tcp相关选项
  • -u (udp)仅显示udp相关选项
  • -n 拒绝显示别名,能显示数字的全部转化为数字
  • -l 仅列出在Listen(监听)的服务状态
  • -p 显示建立相关链接的程序名

例如查看 8000 端口的情况,使用以下命令:

1
2
# netstat -tunlp | grep 8000
tcp 0 0 0.0.0.0:8000 0.0.0.0:* LISTEN 26993/nodejs

更多命令:

1
2
3
netstat -ntlp   //查看当前所有tcp端口
netstat -ntulp | grep 80 //查看所有80端口使用情况
netstat -ntulp | grep 3306 //查看所有3306端口使用情况

设置开机自启动

shell 启动时自启动

不建议使用: 因为每次启动shell都会启动, 而像clash这样的程序只需要执行一次即可, 并且如果多个用户执行, 会导致后执行clash的shell执行失败.

  1. 打开 ~/.bashrc./.zshrc

  2. 在文件末尾添加又在每次用户登录时执行的命令, 如

    1
    nohup clash &> /dev/null &
  3. source ~/.bashrcsource ~/.zshrc以使更改生效

使用”启动应用程序偏好设置”

(Startup Applications Preferences)

  1. Startup Applications Preferences 的配置信息通常存储在 ~/.config/autostart 目录中的 .desktop 文件中. 每个启动的应用程序都有一个相应的 .desktop 文件,该文件包含有关应用程序启动方式的信息。

添加文件 vim <startup_program>.desktop, 添加如下配置

1
2
3
4
5
6
7
8
9
10
[Desktop Entry]
Type=Application
Exec=<your command>
Hidden=false
NoDisplay=false
X-GNOME-Autostart-enabled=true
Name[en_US]=<My Program>
Name=<My Program>
Comment[en_US]=<My startup program>
Comment=<My startup program>

如:

1
2
3
4
5
6
7
8
9
Desktop Entry]
Type=Application
Exec=nohup clash &> /dev/null
Hidden=false
NoDisplay=false
X-GNOME-Autostart-enabled=true
Name[en_US]=clash
Name=clash
Comment[en_US]=clash

Exec 行指定了要在启动时运行的程序的路径

使用 systemctl 方式 (RECOMMNAD)

采用systemctl的方式

强烈建议看看这个文档,里面介绍了一些参数的具体含义.

  1. 准备工作

    1. 写好脚本(假设脚本名为 exec_clash.sh)或将程序放入本地可以运行, 这里以clash为例, 其中, clash位于 /usr/local/bin/clash

      exec_clash.sh 中的 exec_clash 是可根据具体脚本的功能改为相应的名字

    2. 若是脚本, 则赋予脚本运行权限: chmod +x exec_clash.sh

  2. 配置

    1. 编写一个 <clash>.service, 内容如下:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      [Unit]
      Description=clash

      [Service]
      Type=simple
      User=qeuroal
      ExecStart=/usr/local/bin/clash
      Restart=always
      RestartSec=30
      StartLimitInterval=0

      [Install]
      WantedBy=multi-user.target graphical.target

      说明

      1. User: 表示以哪个用户启动,不写默认是root. 而用户名也决定了程序启动去哪里读取相应的配置

      2. ExecStart: 就是要执行的语句。

        由于为脚本赋予了x(可执行)权限, 因此, ExecStart后面的内容可以直接写成脚本的绝对路径

      3. Restart=always: 只要不是通过systemctl stop来停止服务,任何情况下都必须要重启服务,默认值为no。还可以配置有条件重启,具体参考上述文档。

      4. RestartSec=5: 重启间隔,比如某次异常后,等待5(s)再进行启动,默认值0.1(s)

      5. StartLimitInterval: 无限次重启,默认是10秒内如果重启超过5次则不再重启,设置为0表示不限次数重启

    2. 拷贝 clash.service/lib/systemd/system, 需要注意权限问题

    3. 修改配置文件后需要重加载配置: sudo systemctl daemon-reload

    4. 设置开机自启: sudo systemctl enable clash.service

      之后就可以直接重启了

    5. 相关操作

      操作 命令
      启动 sudo systemctl start clash.service
      停止 sudo systemctl stop clash.service
      查看状态 sudo systemctl status clash.service
    6. 测试自动重启功能

查看程序启动命令

最佳解决方法

大多数默认应用程序将具有位于/usr/share/applications中的.desktop文件。

要了解在启动其中一个应用程序时将运行的相应终端命令,请打开文件浏览器Nautilus,然后右键单击应用程序的图标以在上下文菜单中选择“属性”。这将为您提供所需的所有详细信息(此处显示将运行gnome-control-center -overview的系统设置)

次佳解决方法

如果通过存储库或dpkg安装了应用程序,则可以使用以下命令:

1
dpkg -l | grep "<application name>"

这将搜索所有已安装的应用程序,并搜索其描述;搜索描述是这里的重要部分,因为描述通常包含应用程序的名称,即使运行它的”command”不包含应用程序名称。

例:
在GNOME中,有一个名为Disk Usage Analyzer的应用程序。但是,从终端运行它的命令不是disk-usage-analyzer。要查找其命令,您可以运行:

1
dpkg -l | grep "disk usage"

输出应包含此条目:

1
2
alaa@aa-lu:~$ dpkg -l | grep "disk usage"
ii baobab 3.6.4-0ubuntu1 i386 GNOME disk usage analyzer

看第二栏。实际运行磁盘使用率分析器的命令是baobab

参考目录

移动隐藏文件

1
mv * .[^.]* <destination_directory>

解释

1、mv命令的最后一个参数是要移动文件的目标位置;
2、第一个 * 匹配除了隐藏文件的所有文件;
3、隐藏文件使用 .[^.]* 匹配
4、匹配隐藏文件用 .[^.]* 为什么不用 .*: .* 会匹配目录 ...
5、.[^.]* 的意思是:以 . 开头,加不是 . 的一个任意字符,再加其他任意字符

参数补充

参数说明:

参数 说明
-b 当目标文件或目录存在时,在执行覆盖前,会为其创建一个备份。
-i 如果指定移动的源目录或文件与目标的目录或文件同名,则会先询问是否覆盖旧文件,输入 y 表示直接覆盖,输入 n 表示取消该操作。
-f 如果指定移动的源目录或文件与目标的目录或文件同名,不会询问,直接覆盖旧文件。
-n 不要覆盖任何已存在的文件或目录。
-u 当源文件比目标文件新或者目标文件不存在时,才执行移动操作。

clash API 使用

教程

首先,阅读Clash的API的文档RESTful - Proxies

GET 获取所有代理

1
/proxies

PUT 切换 Selector 中选中的代理

1
/proxies/<name>

(这边的name可以为节点名称,也可以为Selector。只要在proxies/后直接加上字符串就可以,不需要引号或者:

当前接口只支持切换 Selector 中的代理

Path Parameters Body Parameters
name name
string string
代理Selector名称(大小写敏感) 要切换的代理名字

接着,curl使用指南 curl 的用法指南

最后,使用curl切换节点, 使用/proxies获取所有可用代理,然后curl发送PUT请求解决战斗。

Example

1
curl -X PUT -H "Content-Type: application/json" -d '{"name":"节点名"}' http://localhost:port/proxies/<name>

-H 添加 HTTP 请求的标头Content-Type: application/json,根据链接2,不设置标头为application/json可能会有问题。

-d 参数用于发送 POST 请求的数据体。

最后的网址为clash的external-controller的网址端口,最后Selector为要选择的proxy-groups的名称。

实际指令类似下面这条:

  • 获取命令

    1
    curl -X GET -H "Content-Type: application/json" http://127.0.0.1:9090/proxies -o get.json
  • 更改节点

    1
    curl -X PUT -H "Content-Type: application/json" -d '{"name":"香港-08"}' http://127.0.0.1:9090/proxies/国外流量 -o put.json

所有命令

1
2
3
4
5
curl -X PUT -H "Content-Type: application/json" -d '{"name":"香港-08"}' http://127.0.0.1:9090/proxies/国外流量 -o put.json
curl -X PUT -H "Content-Type: application/json" -d '{"name":"香港-08"}' http://127.0.0.1:9090/proxies/国外流量

curl -X GET -H "Content-Type: application/json" http://127.0.0.1:9090/proxies -o get.json
curl -X GET -H "Content-Type: application/json" http://127.0.0.1:9090/proxies

reference: sakronos

内存泄露相关

  • valgrind

汇编反汇编相关

  • objdump

debug相关

  • gdb
  • address2line

镜像、容器与仓库

通俗解释:镜像就类似操作系统光盘介质,容器相当于通过光盘安装后的系统。

  • 通过光盘(镜像),我们能在不同机器上部署系统(容器),系统内的操作只会保留在当前的系统(容器)中,

  • 如果要升级系统,需要使用到光盘(镜像),但是可能会导致操作系统(容器)的数据丢失。

Secure Shell (SSH) 是一个网络协议,它主要被用来加密客户端和服务端之间的连接。 在客户端和服务端的每一次交互都被加密。

这个教程解释了如何在 Ubuntu 机器上启用 SSH。

启用 SSH 将会允许你远程连接到你的系统,并且执行管理员任务。你将能够通过 scpsftp安全传输文件。

在 Ubuntu 上启用 SSH

默认情况下,当 Ubuntu 最初被安装的时候,通过 SSH 进行远程访问是不被允许的。在 Ubuntu 上启用 SSH 非常的简单直接。

以 root 或者其他 sudo 用户身份执行下面的步骤,在你的 Ubuntu 系统上安装并且启用 SSH。

01.使用Ctrl+Alt+T打开终端,并且安装openssh-server软件包:

1
2
sudo apt update
sudo apt install openssh-server

当被提示时,输入你的密码并且按 Enter,继续安装。

02.一旦安装完成,SSH 服务将会被自动启动。你可以验证 SSH 是否正在运行,输入:

1
sudo systemctl status ssh

输出将会告诉你服务正在运行,并且启用开机启动:

1
2
3
4
● ssh.service - OpenBSD Secure Shell server
Loaded: loaded (/lib/systemd/system/ssh.service; enabled; vendor preset: enabled)
Active: active (running) since Mon 2020-06-01 12:34:00 CEST; 9h ago
...

q返回命令行。

03.Ubuntu 自带一个配置防火墙配置工具,称为 UFW。如果防火墙在你的系统上被启用,请确保打开了 SSH 端口:

1
sudo ufw allow ssh

就这些。现在你可以从任何远程机器上通过 SSH 连接到你的 Ubuntu 系统。Linux 和 macOS 系统默认都安装了 SSH 客户端。想要从一个 Window 机器上连接,使用一个 SSH 客户端,例如:PUTTY

连接到 SSH 服务器

想要在局域网内连接到你的 Ubuntu 机器,以下面的格式输入 ssh 命令,加上用户名和 IP 地址。

1
ssh username@ip_address
1
确保你将`username`修改成你自己的用户名,`ip_address`修改成你安装了 SSH 的 Ubuntu 机器的 IP 地址。

如果你不知道你的 IP 地址,你可以使用ip命令轻易地找到它:

1
ip a

你可以从输出中看到,系统 IP 地址是10.0.2.15

一旦你找到 IP 地址,通过运行下面的ssh 命令登录远程机器:

1
ssh linuxize@10.0.2.15

当你第一次连接时,你将看到下面的信息:

1
2
3
The authenticity of host '10.0.2.15 (10.0.2.15)' can't be established.
ECDSA key fingerprint is SHA256:Vybt22mVXuNuB5unE++yowF7lgA/9/2bLSiO3qmYWBY.
Are you sure you want to continue connecting (yes/no)?

输入yes并且你将会被提示输入你的密码:

1
2
Warning: Permanently added '10.0.2.15' (ECDSA) to the list of known hosts.
linuxize@10.0.2.15's password:

一旦你输入密码,你将会看到默认的 Ubuntu 消息:

1
2
3
4
5
6
Welcome to Ubuntu 20.04 LTS (GNU/Linux 5.4.0-26-generic x86_64)

* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
...

现在你可以登录到你的 Ubuntu 机器上。

连接到 NAT 后面的 SSH

想要通过互联网连接到你的 Ubuntu 机器,你需要知道你的公网 IP 地址,并且配置你的路由器接收端口22的数据,并且发送它到正在运行 SSH 的 Ubuntu 机器。

想要获取你尝试通过 SSH 连接的机器的公网 IP,在这个机器上访问 URL 地址:https://api.ipify.org

当设置端口转发时,每一个路由器都有不同的方式来设置端口转发。你应该参考你的路由器文档,关于如何设置端口转发的信息。简单来讲,你应该输入之前设置的 SSH 端口号 22,以及之前服务器的私有 IP 地址。

一旦你找到 IP 地址,配置你的路由器,输入:

1
ssh username@public_ip_address

如果你将你的机器暴露在互联网中,你最好采取一些安全措施。最基础的一个措施就是配置你的路由器接受一个非标准端口的 SSH 流量,并且转发到你运行 SSH 服务的机器的端口22。

你也可以设置 SSH 密钥公钥验证方式,之后你就可以不使用密码就可以连接到你的 Ubuntu 机器上了。

在 Ubuntu 上禁用 SSH

想要在你的 Ubuntu 系统上禁用 SSH 服务器,简单停止 SSH 即可,输入:

1
sudo systemctl disable --now ssh

稍后,你可以重新启用,输入:

1
sudo systemctl enable --now ssh

SSH登录

SSH 无密登录

step1 客户端生成公私钥

本地客户端生成公私钥:(一路回车默认即可)

1
ssh-keygen

生成之后会在用户的根目录生成一个 “.ssh“的文件夹,进入”.ssh“会生成如下几个文件:

1
cd ~/.ssh

下创建两个密钥:

  1. authorized_keys: 存放远程免密登录的公钥,主要通过这个文件记录多台机器的公钥
  2. id_rsa : 生成的私钥文件
  3. id_rsa.pub : 生成的公钥文件
  4. know_hosts : 已知的主机公钥清单

ps

ssh公钥生效需满足至少下面两个条件:

  • .ssh 目录的权限必须是700
  • .ssh/authorized_keys 文件权限必须是600

step2 上传公钥到服务器

这里测试用的服务器地址为:192.168.32.32

用户为:root

方法1

1
ssh-copy-id -i ~/.ssh/id_rsa.pub <remote_ip>

上面这条命令是写到服务器上的ssh目录下去了

1
2
cd ~/.ssh
vim authorized_keys

可以看到客户端写入到服务器的 id_rsa.pub (公钥)内容。

方法2

使用命令ssh-copy-id <remote_ip>

1
ssh-copy-id root@192.168.32.32

方法3

通过scp将内容写到对方的authorized_keys文件中

1
scp -p ~/.ssh/id_rsa.pub root@<remote_ip>:/root/.ssh/authorized_keys

step3 测试免密登录

客户端通过ssh连接远程服务器,就可以免密登录了。

1
ssh root@192.168.32.32

设置指定用户

step1 配置SSH服务器

编辑SSH服务器配置文件(通常位于/etc/ssh/sshd_config)。

1
$ sudo vim /etc/ssh/sshd_config

确保以下行未注释(没有#):

1
2
PubkeyAuthentication yes
PasswordAuthentication yes

这允许使用SSH密钥和密码进行身份验证。

step2 设置Match

在配置文件的末尾添加Match块,限制只允许用户user1, user2, user3使用密钥登录。您可以这样做:

1
2
Match User user1,user2,user3
PasswordAuthentication no

1
2
3
4
5
6
7
8
Match User user1
PasswordAuthentication no

Match User user2
PasswordAuthentication no

Match User user3
PasswordAuthentication no

这将禁用user1,user2,user3用户的密码登录。其他用户将按照默认设置进行身份验证,允许密码登录。

多个用户也可以单独

step3 重启SSH服务

保存配置文件并重启SSH服务,以使更改生效:

1
$ sudo systemctl restart ssh

现在,user1,user2,user3用户只能使用其SSH密钥进行身份验证,而其他用户仍然可以使用密码进行身份验证。

请确保在执行此操作之前,您已经测试过SSH密钥对的工作方式,并且确保您至少有一种方法可以访问服务器,以防止自身被锁定。

SSH设置环境变量

方法1

~/.ssh/config 中设置如下内容:

1
2
Host *
SetEnv TERM=xterm-256color

它的作用是为所有主机(Host * 表示匹配所有主机)设置一个环境变量 TERM, 其值为 xterm-256color, 具体含义如下:

  • Host *: 这是一个通配符规则,表示该配置适用于所有远程主机。 如果你只想针对特定主机应用配置,可以将 * 替换为主机名或 IP 地址。
  • SetEnv TERM=xterm-256color : SetEnv 是 SSH 配置指令, 用于在连接到远程主机时传递环境变量. TERM=xterm-256color 设置了终端类型为 xterm-256color, 这是一种支持 256 色的终端模拟器类型。这对于需要彩色输出的程序(如 vim、tmux 等)非常重要。

TERM=xterm-256color 的是为了解决远程连接用户时, 键入字符错乱的问题

方法2

ssh 连接时, 使用命令行 -o 选项设置环境变量: ssh -o SetEnv="TERM=xterm-256color" user@hostname

SSH 上传下载

上传

上传本地文件到服务器

格式:scp 要上传的文件路径 用户名@服务器地址:服务器保存路径

例如:把本机 /home/test.txt 文件上传到 192.168.0.101 这台服务器上的 /data/ 目录中

1
scp /home/test.txt root@192.168.0.101:/data/

上传目录到服务器

格式:scp -r 要上传的目录 用户名@服务器地址:服务器的保存目录

例如:把 /home 目录上传到服务器的 /data/ 目录

1
scp -r /home root@192.168.0.101:/data/

下载

从服务器上下载文件

格式:scp 用户名@服务器地址:要下载的文件路径 保存文件的文件夹路径

例如:把 192.168.0.101 上的 /data/test.txt 的文件下载到 /home(本地目录)

1
scp root@192.168.0.101:/data/test.txt /home

从服务器下载整个目录

格式:scp -r 用户名@服务器地址:要下载的服务器目录 保存下载的目录

例如:把 192.168.0.101 上的 /data 目录下载到 /home(本地目录)

1
scp -r root@192.168.0.101:/data  /home/

注:目标服务器要开启写入权限。

访问服务器的 127.0.0.1:port

服务器 port 允许外部 IP 访问时

假设目标服务器的 ip 地址为: 192.168.32.32, port 为 8080

则在本地的浏览器地址栏输入: <ip>:<port>, 这里输入: 192.168.32.32:8080

服务器 port 不允许外部 IP 访问时

  1. 将服务器 port 端口转发到本地 port

    如将服务器 9090 端口转发到本地 19090.

    1
    ssh -L 19090:127.0.0.1:9090 <ip>:<port>
  2. 地址栏输入: localhost:19090127.0.0.1:19090

设置特定用户的sshd_config

1
2
Match User <用户名>
PasswordAuthentication yes

透过跳板机访问服务器

方法1 (简单却暴力)

很多环境都有一台统一登录跳板机,我们需要先登录跳板机,然后再登录自己的目标机器.登录流程如下

1
2
ssh root@跳板机ip 
ssh root@自己的目标机器ip

方法2 (使用端口转发)

  1. 首先通过 ssh 连接跳板机, 并设置端口转发, 如将本地端口 2222 通过跳板机 (132.60.171.142) 转发到服务器 (192.168.2.28) 的 22 端口, ~/.ssh/config 配置如下:

    1
    2
    3
    4
    5
    Host linkrm
    HostName 132.60.171.142
    User qeuroal
    Port 15220
    LocalForward 2222 192.168.2.28:22

    在本地运行命令: ssh linkrm

  2. 通过 ssh 连接本地端口 2222, 访问服务器 (192.168.2.28), ~/.ssh/config 配置如下:

    1
    2
    3
    4
    5
    Host rm
    HostName localhost
    User qeuroal
    Port 2222
    LocalForward 16006 127.0.0.1:6006

    在本地另开一个终端, 并运行命令 ssh rm

方法3 (使用 ProxyCommand)

有一台机器A,欲与机器C建立SSH连接,但由于隔离限制(比如”存在防火墙”)该SSH连接不能直接建立。ssh命令的”ProxyCommand”选项被设计用来解决以上问题。

通过“ProxyCommand”选项,机器A能够灵活使用任意代理机制与机器C上的SSH Server端口建立连接,接着机器A上的SSH Client再与该连接进行数据交互,从而机器A上的SSH Client与机器C上的SSH Server之间建立了与一般“直接SSH连接”不太一样的“间接SSH连接”。不过由于“间接SSH连接”的透明性,逻辑上可认为机器A上的SSH Client与机器C上的SSH Server建立了“直接SSH连接”。
“直接SSH连接”示意图如图1,“间接SSH连接”示意图如图2。

常使用代理机制有两种,接下来进行介绍。

常使用代理机制

代理机制1

ProxyCommand 选项值形式为 ssh -W C:CPort -l USER -i PRIVATE_KEY -p BPort B. 原理是 ssh 命令自提供的代理机制,在机器A上另外单独建立与B的SSH连接(使用-l USER -i PRIVATE_KEY -p BPort B这些参数),该SSH连接的B端侧与机器C上的SSH Server端口(即C:CPort)建立连接,该SSH连接的A端侧与机器A上的SSH Client(即w最终欲建立’间接SSH连接’在机器A上的SSH Client”)建立连接。

假定A上ssh_config配置文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
Host B
HostName 132.60.171.142
User qeuroal
Port 15220
IdentityFile ~/.ssh/id_dsa

Host C
HostName 192.168.2.28
User qeuroal
Port 22
IdentityFile ~/.ssh/id_rsa
ProxyCommand ssh -W %h:%p B

在A上执行 ssh C 命令,发现A与C成功建立SSH连接。根据以上所述,此时在A上应该有两个SSH进程,一个对应于”A与B的SSH连接”,另外一个对应于”A与C的SSH连接”。在A上执行 ps -ef | grep 'ssh' 命令,得到如下结果,得证。

1
2
7851  7689 15:55 S pts/10   ssh C
7852 7851 15:55 S pts/10 ssh -W C:1046 B

代理机制2

“ProxyCommand”选项值形式为”nc -X 5 -x B:BPort C CPort”,原理:利用”nc”命令,在机器A上使用”nc”命令与代理服务器(即”-x B:BPort”,通过”-X 5”参数来指定与代理服务器的通信协议为”SOCKS4/SOCKS5/HTTPS”)建立代理连接,该代理连接的B端侧与机器C上的SSH Server端口(即”C CPort”)建立连接,该代理连接的A端侧与机器A上的SSH Client(即”最终欲建立‘间接SSH连接’在机器A上的SSH Client”)建立连接。
假定A上ssh_config配置文件内容如下:

1
2
3
4
5
6
Host C
HostName %h
User dsl
Port 1046
IdentityFile ~/.ssh/id_rsa
ProxyCommand nc -X 5 -x B:8989 %h %p

在A上执行ssh C命令,发现A与C成功建立SSH连接。根据以上所述,此时在A上应该有一个NC进程和一个SSH进程,前者对应于”A与B的代理连接”,后者对应于”A与C的SSH连接”。在A上执行ps -ef | grep -e 'ssh' -e 'nc'命令,得到如下结果,得证。

1
2
3
$ ps -ef | grep -e 'ssh' -e 'nc'
8816 8089 16:08 S pts/10 ssh C
8817 8816 16:08 S pts/10 nc -X 5 -x B:8989 C 1046

ssh命令”端口转发”和”ProxyCommand”选项之间的关系

端口转发包括:本地转发,远端转发和动态转发。其中”本地转发”和”远端转发”属于”静态转发”(因为转发目标端口是固定的)。
ProxyCommand选项能够使用基于”动态转发”的代理机制(在外面封装nc命令层),而不能使用基于”静态转发”的代理机制。

参考文献:

FAQ

ssh 连接 remote host identification has changed

找到.ssh目录,下面有一个known_hosts文件,删除 ~/.ssh/known_hosts 文件,或者如果你可以判断出known_hosts中原ssh服务器的公钥,删去那部分,

Double and random letters when typing on a SSH MacOS -> Ubuntu connection

这里, 设置远程机器的 TERM 变量为 xterm-256color.

0%