Linux
介绍
内存
虚拟内存 = 物理内存 + 交换空间
交换空间 = 交换空间
当用户访问某一个程序内存时,需要访问物理内存,而不是交换内存,如果物理内存没有,而交换内存有,则会将交换内存中的程序
加载进物理内存供用户使用,同样,当一个程序长期未访问,内核会将物理内存中的程序放入到交换内存中,使用的时候再加载进来!
GNU工具
GNU工具十分重要,是我们操作linux的关键桥梁,可以说我们写的所有linux命令和shell脚本都是通过GNU工具来处理linux内核!
GNU工具提供了很多种Shell,其中默认的是bash shell,也是我们要学习的
Linux版本
核心发布版本大多数并不满足企业使用,故企业经常使用基于核心发布版本上构建的发行版:
如下CentOS就是基于Red Hat构建出的专用于企业的免费版本
还有一种操作是电脑不用安装linux,而是将linux软件安装到一个移动硬盘上,电脑直接插入硬盘,开机时选择基于硬盘启动即可轻松使用linux操作系统,之前在哈尔滨出差时,那边的开发人员汪精忠就是用此方法使用linux:
Shell
Shell本质
详细看:http://c.biancheng.net/view/706.html
shell连接其他程序不难理解,比如在shell中执行:java -cp xxx.jar 命令
实际上就是shell使用了java的命令
Shell和bash关系
详细看:https://wangdoc.com/bash/intro.html
Shell 和 系统/bin 命令的异同
区别是:内部/外部命令
内部是shell自身提供的命令,例如exec history which命令等,这种命令which 查找是找不到的,因其是bash提供的shell内部命令,而外部就是 /bin/下linux内置的命令,当内部命令找不到时就会使用通过环境变量来使用外部命令,如果想判断一个命令是内部还是外部命令可以通过 type -a 命令查看
若要使用外部命令可以通过:/bin/pwd 实现
文件系统
基本命令
多个命令可以写在一行:
pwd; ll; who
如果要查看目录下文件按照修改时间排序可以使用:ll -t [time的意思]。默认第一行为最近日期
如果要按照日期倒序,可以使用 ll -rt [r是reverse]
若要通过文件大小排序查看,则使用 ll -h , 如果倒序使用 ll -lr
-R 可以递归查看所有子目录及文件,十分方便
file是个挺强的命令,可以看到文件的编码和类型
cat命令:
tail命令:
进程监控
ps
**ps命令:ps -ef **
小技巧:ps -ef --forest 可层级显示子父进程关系
top命令
top默认是CPU排序,若要想指定字段排序,需要按f键,此时会展示所有字段列表,上下键选择要排序的字段,然后按s键保存
后按q退出,此时就可以展示选中字段排序了
结束进程,开发的java程序应该有处理关闭进程的逻辑!如何优雅关闭进程看:https://blog.csdn.net/carlislelee/article/details/52688693
top 高级用法
1、执行top -c ,显示进程运行信息列表
2、top -Hp 10765 ,显示一个进程的线程运行信息列表
这点在用于排查java进程的时候尤其有用,例如通过top -c 发现第一个java进程[139270]占用了太多CPU,想看一下此进程下是哪些线程导致的问题时就可以用-Hp来查看
top -Hp 139270
此时可以看到此进程下运行的所有线程,这里假设159483线程占用过多资源,此时就可以使用jstack来查看此线程的状态
磁盘管理
磁盘常用命令
查看物理机盘符情况:fdisk -l ; 需要结合lsblk命令查看,因为有些盘符是从大盘符上分出来的,如下的centos-root
查看物理机磁盘大小:lsblk;可以看到磁盘依赖关系
df -h 查看磁盘各个设备使用情况,此命令可以发现哪个目录导致磁盘满,十分有用
du 命令用于查看特定目录磁盘的使用:当和df命令结合时,可以解决大部分磁盘满问题
du -sh 命令可以查看当前目录和指定目录的使用大小,十分方便!
du -sh * :查看当前目录所有文件或子目录使用大小,十分好用,可以看出是usr文件过大
测试磁盘读写速度
一、测试写速度:
time dd if=/dev/zero of=/tmp/test bs=8k count=1000000
测试结果:1.3GB/s
二、测试读速度:
time dd if=/tmp/test of=/dev/null bs=8k
测试结果:2.8GB/s
三、测试读写速度:
time dd if=/tmp/test of=/var/test bs=64k
测试结果:1.3GB/s
四、参数说明
①、time 有计时作用,dd 用于复制,从 if 读出,写到 of;
②、if=/dev/zero 不产生 IO,因此可以用来测试纯写速度;
③、同理 of=/dev/null 不产生 IO,可以用来测试纯读速度;
④、将/tmp/test 拷贝到/var 则同时测试了读写速度;
⑤、bs 是每次读或写的大小,即一个块的大小,count 是读写块的数量。
内存
# 以GB显示,如下物理机内存资源为125gb
$ free -g
total used free shared buff/cache available
Mem: 125 48 26 0 50 76
Swap: 0 0 0
句柄数
# 查看文件句柄数
ulimit -n
# 查看有关句柄数的所有信息
ulimit -a
# 修改
sudo vim /etc/security/limits.conf
尾部增加:
* soft nofile 655350
* hard nofile 655350
* soft nproc 655350
* hard nproc 655350
CPU
# 总核数 = 物理CPU个数 X 每颗物理CPU的核数
# 总逻辑CPU数 = 物理CPU个数 X 每颗物理CPU的核数 X 超线程数
# 查看物理CPU个数
cat /proc/cpuinfo| grep "physical id"| sort| uniq| wc -l
# 查看每个物理CPU中core的个数(即核数)
cat /proc/cpuinfo| grep "cpu cores"| uniq
# 查看逻辑CPU的个数
cat /proc/cpuinfo| grep "processor"| wc -l
排序-sort
sort命令默认按字符排序,若要改为数字排序需要加-n,若要降序需要-r
更多详细技巧看:https://www.cnblogs.com/51linux/archive/2012/05/23/2515299.html
搜索文本-grep
注意:grep后面跟要搜索的字符串,不加引号默认就是模糊匹配!如果想通过正则表达式查找需要用字符括起来!
grep命令是查找文本最常用的命令:grep aa test.txt
*grep aa .txt 通过通配符星查找到所有.txt结尾文件!可以通过通配符来查所有日志文件!十分好用
grep -v xxx 文件 去除包含xxx的行,这点在结合ps时非常好用
grep -n xxx 文件 通过-n找到匹配文本,显示其对应的行号
*grep -i aa .txt -C 5 通过-i忽略aa大小写并找到上下文5行
grep -m 10 aa xxx 查找符合aa条件的前10条,当匹配项很多的时候此命令非常好用
grep aa xxx | tail 查找符合aa条件的最后10条,结合管道符非常好用
grep “pattern” file.txt -A 2 查找匹配到的结果及其后2行
grep “pattern” file.txt -B 2 查找匹配到的结果及其前2行
*grep -e aa -e bb .txt -C 5 查找符合aa 或 bb 条件的行以及上下文5行
grep命令本身不提供AND功能。但是,但是我们可以使用管道符进行查找,十分方便:
grep “357e” pentagon/pentagon.log | grep tb_025ccc7986054544b675a9a776db5e5e
还可以使用 -E 正则选项可以实现AND操作:
*grep -m 10 -E '357e.tb_025ccc7986054544b675a9a776db5e5e’ pentagon/pentagon.log
其他操作:
在实战中grep还常常和ps 结合使用,例如:
$ ps -efl | grep 16364
1 S root 16364 2 0 80 0 - 0 worker 8月16 ? 00:00:00 [kworker/16:0]
0 S dig 19719 17485 0 80 0 - 28164 pipe_w 11:08 pts/2 00:00:00 grep --color=auto 16364
$ ps -efl | grep 16364 | grep -v grep
1 S root 16364 2 0 80 0 - 0 worker 8月16 ? 00:00:00 [kworker/16:0]
wc计数
wc在计数层面十分常见,使用频率较高
除了统计文件数量外,更多情况我们是结合管道符与其他命令配合使用,如下: 统计当前服务器打开文件数
lsof
在查看服务器文件句柄数 和 查看端口进程时经常使用lsof命令
lsof 命令根据进程名称查看该进程打开的文件句柄数及使用情况,如下:
sudo lsof -p <pid>
-n 参数可以避免解析主机名和端口号
如果只输入lsof命令,则会打印该服务器当前系统中打开的文件(或者说句柄)的信息
压缩
最常用的还是tar 命令:
解压: tar -zxvf xxx.tar.gz -C /tmp/xxx
压缩: tar -zcvf xxx.tar.gz a.txt b/
压缩时要压缩的文件在最后面空格分割
jar包解压
unzip xxx.jar -d 解压到的目录下【此目录可以自动创建】
反编译class文件
javap xx.class
shell子父进程
通过–forest可以很清楚的看到子父进程关系:
在生成子shell进程时,只有部分父进程的环境被复制到子shell环境中。这会对包括变量在内的一些东西造成影响,后面会详细讲
创建子进程
()括号虽然可以创建子进程,但是会阻塞当前进程的使用,比如: (sleep 10)命令会让主进程阻塞10秒,若想解决此问题可以通过子进程后台运行的方式解决,后面会讲
进程后台运行
后台运行的核心在于 & 字符,可以将任务置于后台,此时可以通过ps查看
还有就是&的后台运行只会在当前主进程存在的基础上,如果此终端退出,则进程直接结束,故一般生产上会使用nohub命令
关于生产使用后台运行的方式详细看:https://app.yinxiang.com/shard/s34/nl/31250097/cbd56fcf-9f3c-42cd-a7e9-c63a1f34e694/
history命令
bash命令的历史记录是先存放在内存中,当shell退出时才被写入到历史文件中,文件位置为当前用户家目录下的.bash_history
当当前bash退出时就会写入到.bash_history文件中,若想强行写入需要执行: history -a选项
假如用户打开多个相同用户的bash窗口,多个窗口之间并不会共享历史数据,这是因为每个窗口的历史记录都在内存中,如果想要共享可以先通过history -a强制写入到历史文件,然后在别的窗口中通过history -n重新加载历史文件,即可完成复用
alias别名
别名命令十分好用,就像sql中的视图一样,将负责的命令起一个别名,可以大大减少我们命令的输入量,例如切换用户:
通过alias命令可以看到内置的别名,可以发现常用的:ll 和 ls 也被内置了,其中ls成了ls --color=auto
这才导致我们使用ls看到的列表式有颜色的,如果使用原生的/bin/ls是没有颜色的
创建别名:alias ll=‘ls -lF’
若别名已存在,则自动覆盖已存在的别名
注意:如果只到这一步,则此别名不是永久别名,终端退出后就会消失,永久别名方式参考下图:
环境变量
全局&局部变量
前言
linux中氛围全局变量和局部变量,全局变量是可以在子父进程中共享,但是局部变量不可以共享
并且子进程中对全局变量的删除或者修改,不会影响父进程,注意这里指的删除修改并不是改配置文件,而是命令行中创建的全局变量!
注意:通过命令的方式创建的全局变量并不会永久保存,当终端关闭后就会消失!
注意:全局变量要大写,而局部变量要小写
设置局部变量
命令:xx=xx
设置全局变量
设置命令:export xx=xx
子进程中对全局变量的删除或者修改,不会影响父进程,注意这里指的删除修改并不是改配置文件,而是命令行中创建的全局变量
删除环境变量
unset 变量名
PATH变量
path变量是用来查找命令的默认变量,当你输入一个外部shell命令例如spark-shell,系统就会从path变量中查找了
系统环境变量&用户环境变量
理解
若想设置永久环境变量就需要保存在文件中,文件由以下几种组成
注意:/etc/profile是一定会加载的,至于其他文件则会根据当前shell情况来加载环境变量,大致分为三种
/etc/profile文件中有for循环,去循环调用/etc/profile.d目录下的脚本文件,用来加载环境变量,故如果我们要创建系统环境变量,不要直接更改/etc/profile文件,而是应该在/etc/profile.d目录下新增脚本文件即可
登录shell
在加载完/etc/profile文件后,登录shell就会获取用户目录下的其他文件,这里注意,如果找到其中一个文件,余下文件则会被忽略,这里没有.bashrc文件,这是因为bashrc文件是在.bash_profile文件中指定加载的!
可以看出.bashrc文件是在.bash_profile文件中加载的!
交互式shell
非交互式shell【即子shell】
非交互式也就是子shell进程[sh xxx.sh],当用户通过 sh xxx.sh方式执行脚本任务时,其实就是子shell进程,此时子shell会获取父进程的所有全局环境变量!
子shell验证
先上结论:在脚本内部通过 $() () 来执行的子shell是可以获取到局部变量的,只有像sh xxx.sh 这种是获取不到局部变量的
# 看一下脚本,根据外部aaa全局变量获取值
$ cat test.sh
#!/bin/bash
echo $aaa
bbb=$(ls /${
aaa})
echo $bbb
# 此时定义一个局部变量
$ aaa=tmp
$ echo $aaa
tmp
# 然后执行,可以发现子shell没有获取到
$ sh test.sh
Applications Library System Users Volumes bin cores dev etc home opt private sbin tmp usr var
# 此时再设置成全局变量,可以证明子shell只能继承全局变量
$ export aaa=tmp
$ sh test.sh
tmp
com.adobe.AdobeIPCBroker.ctrl-hzxt com.apple.launchd.qisYqyWdTz com.sogou.inputmethod ev-6ca1cF ev-KDyAuV mysql.sock
但是注意,这里说的子shell是真的 ./ 这种启动一个子shell,如果只是当前脚本中的 $() `` 或者 (;😉 的子shell依然可以获取到局部变量!子shell无法更改父类的任何变量
# father脚本
$ cat father.sh
#!/bin/bash
dir=tmp
echo father: $(ls /$dir) # 使用子shell,然而这种子shell是可以获取到局部变量的
# ()括起来默认是使用子shell执行多个命令,尝试使用父shell局部变量;然而这种子shell是可以获取到局部变量的
(echo $dir; dir=asdf)
# 再次打印dir变量
echo $dir
# 执行真正的子shell,这种子shell不能获取到局部变量
sh ./child.sh
# child子脚本
$ cat child.sh
#!/bin/bash
echo child: ${dir}
# 执行命令
$ sh father.sh
father: com.adobe.AdobeIPCBroker.ctrl-hzxt com.apple.launchd.qisYqyWdTz com.sogou.inputmethod ev-6ca1cF ev-KDyAuV mysql.sock
tmp
tmp
child:
永久化系统变量和用户变量设置
source命令
我们修改环境变量文件后的srouce, 其实就是将文件中的内容在当前环境执行一遍
source命令和sh 执行脚本文件不同,sh执行脚本是通过子shell执行脚本内容,而source是在当前bash环境下读取并执行FileName中的命令。
还有环境变量的区别,source中设置的全局环境变量在当前服务中生效,但如果是sh 启动脚本则是子进程创建全局环境变量,当子进程退出后全局变量失效,故source可以在当前进程中加载环境变量!也是我们常用的原因
比如新建一个文件:tsource
ls
aa=aa
bb=bb
pwd
然后执行:source tsource 或者 . tsource
可以看出在source命令是读取文件中的每一样在当前环境中执行
文件权限
用户
创建用户的时候,如果不指定参数,则默认不会创建家目录!需要加上 -m参数,此外建议加上 -c 说明此用户的作用作用
常见命令:useradd -c xxx -m 用户名
默认创建时没有密码,需要通过passwd设置密码:passwd 用户名
通过useradd -D 可以看到系统创建用户时默认参数!其中有意思的是skel,默认新建用户目录的文件
删除用户使用userdel命令,默认只会删除passwd中的数据,并不会删除用户目录!注意不建议使用-r 参数,因为别的用户可能使用此用户目录
用户组
组密码极少情况才会用到,故可以忽略不计;
当新建一个用户时就会产生一个默认组,组名和用户名保持一致,默认组在etc/group文件中不会显示用户列表,在使用useradd创建用户时可以指定将新用户加入某个组中,即一个用户可以加入多个组中!
删除组命令是:groupdel 详细配置通过man groupdel 查看
文件权限
权限更改主要就两个命令:chmod 和 chown
详细使用都可以通过man去查看
父目录权限对子目录的影响
如果子目录child权限是777,但父目录user目录权限是700,则其他目录也无法进入到child目录下!
解决方案:只需要给user目录其他用户增加执行权限即可:chmod o+x user
共享文件
比如我现在bdp/cluster目录下新建一个share共享目录,让所有属于docker组的用户都可以访问,其实很简单,要保证四点:
1、share目录要设置所属组为docker: chown bdp:docker share
2、share目录的组执行权限要改为s,这样在share目录下创建的任何文件或目录都将是docker所属组: chmod g+s share
3、需要访问share目录的用户要加入docker组:usermod -G docker xx用户名
4、share目录的父目录要有其他用户的执行权限,否则其他用户进不来:chmod o+x cluser ; chmod o+x bdp
完成以上操作后,share目录即可对所有docker组用户使用
软件安装及卸载
理解
linux软件安装主要分为两种,这里主要记录redhat的rpm安装方式
yum软件仓库
yum和maven很像,也需要远程仓库,不然从哪下载对应的软件呢?通过yum repolist即可查看远程库
可以看到我们有clickhouse库,这是clickhouse官网提供的
yum查看软件
yum安装
可以加 -y参数,回答全部问题为是
yum更新
yum卸载
yum 依赖冲突
yum和maven很像,在下载一个软件时,如果该软件需要依赖其他软件时会一同下载,那么和maven一样,也可能会出现依赖冲突问题,解决方案如下:
vim编辑文件
基本知识
1、vim 编辑页面中会显示重要信息:会显示当前行数和已读百分比
2、此外,进入到编页面后,没有内容的行会用~波浪线替代:
3、vim不支持并发编辑同一文件,会有冲突
编辑技巧
1、快速定位到文件第一行:gg
2、快速定位到文件最后一行:G
3、快速定位到某一行:num G
4、显示行号::set nu
5、将更改后的文件保存到其他文件::w filename
6、命令模式下删除光标所在的字符:x
7、命令模式下撤回到上一步:u
8、编辑模式下撤回到上一步需要先退出编辑模式然后按:u
9、删除当前行:dd
10、删除指定数量的行:num dd
11、编辑模式下删除光标前的单词:control + w
12、删除所有行,进入命令模式: :%d
13、删除当前行到文件首行:dgg
14、删除当前行到文件末尾:dG
15、删除当前行字符到该行最后一个字符:d$
16、删除当前行字符到该行第一个字符:d0
16、剪切和粘贴,vim模式下删除操作就是剪切,只需按p键即可粘贴
17、复制:v可视模式
18、命令模式下快速换新行并可以编辑:o
19、当查找某个字符串时,需要在命令模式下: /xxx 即可查到,通过n键进行下一个匹配项
20、关于文件内容替换,常用全部替换::%s/old/new/g
21、vim中使用外部命令:!命令
22、通过python格式化文件
:%!python -m json.tool
diff查看两个文件的差异性
$ echo -e aa\\nbb\\ncc > diff1.txt
$ echo -e aa\\nbb\\ndd > diff2.txt
$ diff diff1.txt diff2.txt
3c3
< cc
---
> dd
实战查询进程 | 进程端口 | 进程jar包
1、查看8088端口是被哪个进程占用:lsof -i:8088
2、查看某个进程占用了什么端口:
netstat -nltp | grep pid
3、查看某个微服务名称的进程PID:
ps -ef | grep 微服务名称
4、查看进程详情:
jps -l
5、通过pid找到程序jar包所在目录:ll /proc/27998
find查找文件
find最常用来查找文件,故常用命令为: find 要查找的目录 -name “文件正则表达式”
find ./bdp-dev/ -name "*.c"
netstat
Linux netstat 命令用于显示网络状态。
利用 netstat 指令可让你得知整个 Linux 系统的网络情况。
而我们使用netstat主要是用来查看某个进程占用了什么端口:
netstat -nltp | grep pid
更多使用看:https://www.runoob.com/linux/linux-comm-netstat.html
SSH
ssh主要是用来登录其他服务器,有两种方式:
用户密码登录
# 用户密码的方式顾名思义需要知道用户密码
$ ssh bdp@192.168.1.5
passwd:
Last login: Tue Aug 23 18:44:55 2022 from kube-node5.stargraph
[bdp@kube-node5 ~]$
公钥登录
核心:A想登录到B,就需要将A的公钥发送给B;谁想连,谁发送
公钥登录就很简单,只需要去请求端中将.ssh/id_rsa.pub 中的数据复制到目标服务器的.ssh/authorized_keys中即可无密码登录
为了避免复制错误,我们采用ssh-copy-id 用户名@ip 命令; 两台服务器双向复制这样就可以互相登录
若只是单项,例如mac电脑只想单独登录远程服务,则只需要在mac电脑上将自己的公钥上传到目标服务器即可
# 请求宿主机
ssh-copy-id hzxt@192.168.1.5
ssh 192.168.1.5
Last login: Tue Aug 23 19:10:08 2022 from 10.10.10.73
原理:
SCP
scp是远程拷贝的常用命令,常用于本地复制文件或目录到远程服务器上
scp远程拷贝时需要输入用户名密码, 如果已经设置ssh无密码登陆了,则无需输入密码
# 拷贝文件:
scp test.log bdp@192.168.1.5:~/
# 拷贝目录:
$ scp -r logs/ bdp@192.168.1.5:~/
.DS_Store 100% 6148 271.3KB/s 00:00
naming.log