这次起源于一个挺有意思的Linux命令闯关
Game,我觉得很适合普通人来学习Linux的基本命令, 并且通过基本的man xx去查阅命令, 快速提高使用能力.
0x00.特殊的文件
1.特殊字符文件
我们平常很少见到, 但是其实Linux中真实存在的一些特殊字符的文件, 比如 - , ! , ~ . 那么这种文件, 你直接去cat - 肯定是不行的. 如果这是个文件夹, 你cd - 直接会触发另一个命令. 因为- 这种参数会自动引用stdin/out (位于/dev/stdin` )
1 | #解决办法是通过完整path访问,注意无需绝对路径,比如: |
2.含有空格的文件
这个也比较少见, 但是在win上其实是比较多见的. Linux下有两种常见办法访问这种带空格的文件file name with space.
1 | #1.用字符串整体包起来 |
这里还有一个比较常见的问题, 在vi/vim 中, 大家经常使用查找, 但是你会发现, 并不能直接查找带空格的字符.比如
1 | # 在vim编辑模式 |
0x01.优雅的查找
我们之前已经知道locate 命令比find的效率和使用要简单许多, 但是面对复杂需求的时候. 还是必须知道如何正确,高效的使用find 才行.
1. 查找特定用户/组 & 大小 & 权限的文件
1 | #知道大概的名字 或 知道准确大小(少见). -group也是支持的 |
这里有个很关键的问题, 你直接搜/ 全目录, 会有很多的目录是Permission denied 还有proc这种根本不需要扫的目录. 浪费大量时间, 并且导致显示结果非常糟乱. 那么想到有个好办法过滤.
1 | find / -size 33c -user jin 2> /dev/null #把错误信息滤掉 |
2. 查找依赖包中文件冲突的类
这里以找java某个大项目里提示Class not found 类异常, 如何快速排查为例, 其它类似改一下就行了
1 | # 查找jar包中的文件,请确保jar命令已配系统环境 |
0x02.火眼金睛
大家看东西都想看本质, 那需要有一双火眼金睛, 在Linux中, 许多命令可以显示OS的相关信息, 比如ps , lsof , ip , crontab , top 等等… 可是他们显示的真的是本质/物理的么~ 本着一切皆文件的原则, 命令最后本质也是读取OS的配置文件, 从而显示给用户的, 那我们就要学会直接查看OS的文件信息
1.查看系统的CPU信息
首先, 文件本质是 /proc/cpuinfo , 它会显示每个逻辑CPU(“线程”)的详细物理信息, 这里面重点关注三个参数:
- physical id : 有几个CPU (默认应该是从0开始计数, 也就是说1个就显示0)
- processor : 逻辑CPU的编号 (从0开始–> 1 –> 2 –>3 …)
- cores : 每个CPU的物理核心数
那么, 常用统计命令:
1 | #统计每个CPU物理核心数,单CPU也就是总物理核心数 |
还有一个更简单的方式, 就是通过命令lscpu , 但是要注意这里CPU(s) 代表也是逻辑核心, 物理核心要用socket * core/s 算.
2. 查看内核信息
0x03. 优雅的匹配
这里其实就是说正则, 但是我并没有觉得正则很优雅… 而且我觉得不对着表看, 或者遇到一些特殊写法会非常头疼…
这里就慢慢补吧, 先补充一个比较少见的.
零宽断言 :
?<!,?=,?<=, 后面跟表达式. 比如1
2
3
4
5
6#以下的含义是,匹配 > ,但不匹配 `>
(?<!`)>
# 比如通过>切分字符串
a>b>c --> a b c # 切为3个
a`>b>c --> a`>b c # 切为2个,这时候`>不会被匹配
0x04. 高效的删除
普通的删除就不说了, 批量删除参考下面0x05的操作, 这里说的是另外一些比较特殊但是经常遇到的部分删除操作
1. 高效删除大文件前/后n行
比如现在有一个很大的日志文件没有正常自动切分, 有30G之大把系统磁盘打满了, 我们不想直接把日志文件全部删了, 又想快速释放出空间, 传统做法使用sed 和split , 但是这样通常需要把文件按行全读一次, 并非是我们期望的方式, 参考Stackoverflow后, 我发现使用tail 命令是最佳选择之一:
1 | # tail命令是按需读取, 速度快很多. |
2. 如何替换进程占用中的文件
上面删除是非常高效了, 但是有个很致命的问题, 就是如果你直接去rm bigLog, 然后 mv smallLog ,你会发现磁盘空间并没有直接释放, 因为原日志文件被进程占用了, 你这样做反而埋了个大坑…还得去重启进程, 但是线上很多进程重启都是很麻烦的, 那么最好的做法当然是不要去直接删除原有文件, 那我们该怎么操作呢?
1 | # 1.如果不需要日志, 直接重定向清空 > |
0x05. 批量操作
1. 快速处理文件/夹
经常会遇到这种需求, 一个文件夹里面有从1~12月 的日志文件, 你需要清理1~11月(旧的日志) ,以及很多时候普通命令不支持正则表达式, 那我们怎么去使用呢? 有个很好用的自带工具shopt (shell options)
1 | #默认在系统中是关闭状态的,所以先需要开启支持 |
2. 通配符的使用
这里主要是说一个shell中的天坑, 当然本质也是因为没有好好学习shell的一些语法说明, 在shell中, 双引号("") 定义是不会解析两种字符的:
- 特殊元字符
- 通配符 (*/?为代表)
那么如下的写法就会产生天坑:
1 | path="/path/to/*.txt" |
所以千万记住, 在shell中, 通配符使用要注意, 不要用双引号"" 修饰它, 然后建议文件移动/删除操作都带上-v 参数显示输出, 至少我觉得自己还远不熟悉shell的很多地方, 保险一点比不输出靠谱一些..
3. 批量mv / rename 操作
本质是一个, 但是大家会发现, 批量的mv 操作很头疼, 不仅要写 for 循环, 还要重新用sed/awk去重定向. 比如有如下的需求. 将文件夹内的所有 *.png 重命名为 *.jpg , 你没法直接 mv *.png *.jpg 这样实现.
而且如果需求是修改中间的某个字符, 就更麻烦, 比如下面这个将 . 替换为 _ 的需求, 你会发现异常蛋疼
1 | # 要求将 *.* 的所有文件名, 替换为 *_* |
这里shell目前还没发现比较优雅通用的写法, 但在小伙伴的提醒下, 找到一个特殊可视化办法… 使用 VSCode/Sublime 等IDE工具的多行同时编辑功能, 然后你可以很快写出一个这样的脚本
1 | mv 1.2 1_2 |
不知道看明白了么? 就是多行编辑, 然后手动把 . 都替换为 _ , 然后最前面批量添加 mv, 这样就很简单的实现了各种批量重命名的定制, 虽然你可能说这也太暴力了吧, 但是的确很有效也简单, Linux上用 vim的插件也可以实现这样的效果.
0x0n.配置多版本语言
常见的比如经常会遇到需要python2&3 , JDK7&8 , gcc4/5/6这样的切换操作. 在每个执行脚本的开头去手动导入环境变量肯定是非常鱼的办法… 而且不通用, 所以从这以后, 请一起使用Linux自带的优雅实现方式
下面简单介绍一下alternatives 命令, 注意链接的文件建议放在公有权限目录下(比如/usr/software ), 而不要放在个人文件夹下, 这样链接之后其他用户无法访问.
1 | #如果非root账户,需要sudo,因为本质是修改/etc/alternatives命令 |
需要注意的是, 如果你引用的路径是个人账户下, 比如你的目录是/home/jin/java1.8/bin/ , 那你这样设置之后, 其他用户还是无法直接使用的(需要加sudo), 所以强烈建议使用公有路径. 比如/usr/ 下的.
不过很多人这里并没说清楚的是, 有个很大的隐藏坑, 就是你只是这样设置有两个问题:
- 它只是设置
java这个命令的切换, 其他命令比如javac,javap都不会切换, 你通过javac -version照样会发现版本是不一致的, 这显然不满足我们的需求. (上面我已经补充了) - 你在
~/.bashrc或者/etc/bashrc, 或者/etc/profile/或/etc/profile.d/xx这几个地方, 如果有手动设置export JAVA_HOME=/path/to/jdk1.7, 你会发现就算你把常见的命令都设置一遍, 也可能显示是错误的…. - 如果你发现设置了之后还是不能直接使用
jps, jstack等命令, 那是环境变量缺失问题, 和上文无关, 参考第二步设置一下就行, 比如export PATH=$PATH:/path/to/java1.8/bin
所以综上, 为了确保一个JDK8环境的脚本自动编译运行成功, 你需要设置多个参数, 并且必要的时候你需要删掉/修改被写死的JAVA_HOME 地址. (不同Linux位置可能稍有不同,但是大部分可能我已经列出了..)
未完待续.. 主要是暂时没时间让我玩那个游戏了…
参考链接:
- Linux Game 闯关游戏 (链接失效了, 唔之后再补了)