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.

Win10 使用注册表一键添加小鹤双拼方案

方法1

新建.txt 文件

1
2
3
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Microsoft\InputMethod\Settings\CHS]
"UserDefinedDoublePinyinScheme0"="小鹤双拼*2*^*iuvdjhcwfg^xmlnpbksqszxkrltvyovt"

方法2

  1. win+r 输入 regedit, 打开注册表

  2. 找到 计算机\HKEY_CURRENT_USER\Software\Microsoft\InputMethod\Settings\CHS

  3. 新建字符串值

    名为 UserDefinedDoublePinyinScheme0

    值为 小鹤双拼*2*^*iuvdjhcwfg^xmlnpbksqszxkrltvyovt

按键映射

互换按键reg文件

交换 esc 和 caps lock 按键

1
2
3
4
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout]
"Scancode Map"=hex:00,00,00,00,00,00,00,00,03,00,00,00,3a,00,01,00,01,00,3a,00,00,00,00,00

交换 ctrl 和 caps lock 按键

1
2
3
4
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout]
"Scancode Map"=hex:00,00,00,00,00,00,00,00,03,00,00,00,3a,00,1d,00,1d,00,3a,00,00,00,00,00

取消互换按键

1
2
3
4
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout]
"Scancode Map"=-

原理

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout\ 下新建一个二进制值项: “Scancode Map”

Scancode Map格式说明

1
2
3
4
5
6
00 00 00 00 00 00 00 00 (固定格式)
XX 00 00 00 (XX为修改的总键数+1的16进制数)
XX XX XX XX (修改后的按键扫描码 (在前) + 原按键的扫描码 (在后))
XX XX XX XX (另一个要替换的按键,同上)
......
00 00 00 00 (固定格式)

示例

1
2
3
4
0000 00 00 00 00 00 00 00 00 	
0008 04 00 00 00 1D 00 5B E0
0010 1D E0 5C E0 5B E0 1D 00
0018 00 00 00 00
  1. 00 00 00 00 00 00 00 00: 固定,照写就好

  2. 04 00 00 00: 04代表要修改三个按键的映射,两个是02,一个是01

  3. 1D 00 5B E0

    • 1D 00 : 是修改后的按键扫描码;
    • 5B E0 : 是原按键的扫描码;

    左Ctrl键的扫描码是1D 00,左win键的扫描码5B E0;
    这四个字节代表的意思是将 左win键 替换成 左Ctrl键。

  4. 1D E0 5C E0: 这四个字节代表的意思是将 右win键 替换成 右Ctrl键。

  5. 5B E0 1D 00: 这四个字节代表的意思是将 左Ctrl键 替换成 左win键。

  6. 00 00 00 00: 固定,照写就好

键位16进制对应表

office 365

Office 365 Professional Plus

Office 365 Home Premium

Office 365 Business

office 2021

Office ProPlus 2021

下载地址

Visio Pro 2021

下载地址

Project Pro 2021

下载地址

vagrant 安装

下载地址

安装

  1. 添加 box 到vagrant

    1
    vagrant box add <box_name> <box_path>
    • <box_name>: 为 box 取的名字,供后续创建虚拟机
    • <box_path>: vagrantbox 所在地址
  2. 查看是否添加成功

    1
    vagrant box list
  3. 创建虚拟机

    创建一个目录, 然后在该目录下执行以下命令

    1
    vagrant init <box_name>

    会生成一个 Vagrantfile 文件

  4. 修改 Vagrantfile 文件配置

  5. 启动虚拟机

    1
    vagrant up
  6. 进入虚拟机

    1
    vagrant ssh
    • 默认用户: vagrant
    • 用户密码: vagrant
  7. 关闭虚拟机

    1
    vagrant halt

PS:

  • 每次启动虚拟机需要使用命令行(cmd)进入 Vagrantfile 文件所在的目录,然后再使用 vagrant up 命令启动虚拟机。
  • 关机同理,使用命令行(cmd)进入 Vagrantfile 文件所在的目录,然后再使用 vagrant halt 命令关闭虚拟机。

virtualbox 安装

下载地址

安装教程

双击打开, 默认安装就可以

Ubuntu镜像地址

清华镜像站

fate 官方测试使用的版本为 18.04

vagrant 系统外部可访问

win10系统下的设置

step1. 设置防火墙入站规则

  1. 进入windows 防火墙

  2. 控制面板 -> 系统和安全 -> Windows Defender 防火墙 -> 高级设置 -> 入站规则 -> 文件和打印机共享(回显请求 - ICMPv4-In)

  3. 右键属性 -> 作用域 -> 远程IP地址 -> 下列 IP 地址 -> 添加

  4. 我使用的是 此IP地址或子网

    目的: 仅允许部分用户使用

    如添加: 10.132.0.0/16

测试是否成功配置

即查看是否可以 ping 通

step2. 设置 vagrantfile 为桥接网络

  1. 查看名称或接口索引

    • 方法1

      1
      netsh interface ipv4 show interfaces

      我的这里是 WLAN

    • 方法2 (未测试)

      1. 打开”控制面板”。您可以在开始菜单中搜索”控制面板”,然后选择相应的结果打开它。
      2. 在控制面板窗口中,将视图设置为”小图标”或”大图标”,以便更轻松找到所需的项目。
      3. 找到并点击”网络和共享中心”。
      4. 在左侧导航栏中,点击”更改适配器设置”,以打开网络连接设置。
      5. 在网络连接设置中,您将看到可用的网络适配器列表。查找您希望用作桥接网络的适配器,例如您的有线网卡或无线网卡。
      6. 右键单击所选适配器,并选择”属性”。
      7. 在适配器属性对话框中,找到并选中”Internet 协议版本 4 (TCP/IPv4)”,然后点击”属性”按钮。
      8. 在”Internet 协议版本 4 (TCP/IPv4) 属性”对话框中,您可以看到适配器的IP地址配置。请注意当前配置的详细信息,以便在后续步骤中进行参考。
      9. 在同一对话框中,点击”高级”按钮。
      10. 在”高级 TCP/IP 设置”对话框中,切换到”IP 设置”选项卡。
      11. 在”IP 设置”选项卡中,您将看到网卡的名称和接口索引。记下名称或接口索引,这将用于Vagrantfile中的网络配置。
  2. 设置 config.vm.network "public_network", bright: "WLAN"

    bright: 就是上面的“查看名称或接口索引 ”

  3. 启动/重启虚拟机: vagrant up/vagrant reload

  4. 查看ip地址: ifconfig, 我这里的是 10.132.22.5

  5. 设置Vigrant: config.vm.network "public_network", bright: "WLAN", ip: "10.132.22.5"

    也可以加入子网掩码, 如 config.vm.network "public_network", bridge: "WLAN", netmask: "255.255.0.0", ip: "10.132.22.5"

step3. 更改 vagrant 密码

passwd

1
2
sudo su
passwd vagrant

PS: 更多信息查看 Ubuntu 处理方法

FAQ

  • 华硕主板打不开virtualbox虚拟机的ubuntu安装系统 (虚拟机VirtualBox异常退出解决办法)
  • vagrant ssh 连接 remote host identification has changed
  • 解决vagrant ssh登录时permission deny的问题

华硕主板打不开virtualbox虚拟机的ubuntu安装系统 (虚拟机VirtualBox异常退出解决办法)

vagrant 启动失败 There was an error while executing VBoxManage, a CLI used by Vagrant for controlli……

进入 BIOS 下, 开启 Intel (VMX) 虚拟化技术

vagrant ssh 连接 remote host identification has changed

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

解决vagrant ssh登录时permission deny的问题

  1. 进入虚拟机

    • 方法1: vagrant ssh

      Vagrantfile 文件夹下打开 cmd, 运行命令 vagrant ssh

    • 方法2: virtualbox

      打开 Vagrantfile 中的 virtualbox 显示

      1
      2
      3
      config.vm.provider "virtualbox" do |vb|      
      vb.gui = true # 启动机器时显示 VirtualBox GUI
      end

      然后运行 vagrant up (虚拟机处于关机状态) 或 vagrant reload (虚拟机处于开机状态)

  2. 更改 /etc/ssh/sshd_config 文件下的 PasswordAuthentication no 改为 PasswordAuthentication yes

  3. 重启虚拟机 vagrant reload

不在一个小局域网,而在同一个大局域网

那就把局域网扩大一些, 可以通过设置子网掩码来设置

  • 临时设置子网掩码

    1. 查看网络: ifconfig

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      enp0s3: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
      inet 10.0.2.15 netmask 255.255.255.0 broadcast 10.0.2.255
      inet6 fe80::3b:7bff:feb7:3b2d prefixlen 64 scopeid 0x20<link>
      ether 02:3b:7b:b7:3b:2d txqueuelen 1000 (Ethernet)
      RX packets 523 bytes 61926 (61.9 KB)
      RX errors 0 dropped 0 overruns 0 frame 0
      TX packets 387 bytes 70310 (70.3 KB)
      TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

      enp0s8: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
      inet 10.10.32.32 netmask 255.255.255.0 broadcast 10.10.32.255
      inet6 240c:c983:5:2b48::813 prefixlen 128 scopeid 0x0<global>
      inet6 240c:c983:5:2b48:a00:27ff:feab:56e5 prefixlen 64 scopeid 0x0<global>
      inet6 fe80::a00:27ff:feab:56e5 prefixlen 64 scopeid 0x20<link>
      ether 08:00:27:ab:56:e5 txqueuelen 1000 (Ethernet)
      RX packets 1089 bytes 184808 (184.8 KB)
      RX errors 0 dropped 0 overruns 0 frame 0
      TX packets 85 bytes 12017 (12.0 KB)
      TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

      lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
      inet 127.0.0.1 netmask 255.0.0.0
      inet6 ::1 prefixlen 128 scopeid 0x10<host>
      loop txqueuelen 1000 (Local Loopback)
      RX packets 0 bytes 0 (0.0 B)
      RX errors 0 dropped 0 overruns 0 frame 0
      TX packets 0 bytes 0 (0.0 B)
      TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
    2. 设置子网

      1
      sudo ifconfig enp0s8 10.10.32.32 netmask 255.255.0.0
0%