前言
作为一名后端开发人员,总是不可不免的或多或少的要跟服务器去打交道,从一开始最基本的cd、mv、cp、rm常用命令,到编写一连串的shell脚本,踩过的坑总是让人怀疑人生。今天在这里,我将从分别从基础到高级,以及场景分类来给大家分享一下我在日常中使用Linux时积累的一些经验/知识,本文的面向对象主要为后端开发人员,以及部分实施人员,对于前端开发人员,有需求的也可以参考。不作为专业的Linux指导,只作为接触Linux并尝试在日常学习工作中参考使用。
下文中所有的操作环境为centos7.9,具体为:CentOS-7-x86_64-Minimal-2009,使用其它的系统版本的,请仅供参考。
一、基础命令
文件操作
下述几个命令,是日常使用率最高的几个命令,包含了创建文件/目录,查看/写入文件、删除/复制/重命名文件/目录等常规操作。
cp
cp /home/a.json /home/t #将文件复制到另一个目录 文件存在时会提示
\cp /home/a.json /home/t #将文件复制到另一个目录 强制覆盖
cp -r /home/a /home/b #复制目录
cp -r * /home/b #将当前目录下所有的文件和目录,复制到b下面
cp file1 file2 file3 /home/b #将多个文件复制到b下面
mv
mv /home/a.json /home/t #移动文件到另一个目录
mv /home/a.json /home/t/b.json #移动文件到另一个目录 并重命名
\mv /home/a.json /home/t #移动文件到另一个目录 强制覆盖
mv /home/a /home/b #重命名目录
rm
rm a.json #删除文件,删除前会有提示
rm -f a.json #删除文件,直接删除,没有提示
rm -rf /home/t #删除目录,直接删除,没有提示
ls
ls #列出当前目录文件
ls -a #显示所有文件(包括隐藏文件)
ls -t #文件按时间排序
ls -F #文件以 "/" 结尾
ls -m #文件用 "," 隔开
ls -1 # 数字1, 每行列出一个文件,相对ls列在一行来说
ls -r #倒序排序
ls -R #递归列出文件目录(子文件也一一列出)
ls -l #以列显示
ll #列出文件的详细信息※最为常用
echo
echo "It is a test" #打印出字符串
echo It is a test #同上
echo $JAVA_HOME #打印出变量的值
echo "$JAVA_HOME" #同上
echo '$JAVA_HOME' #会将$JAVA_HOME作为字符串打印出来
echo -e "OK! \n" # -e 开启转义,否则就会变成普通字符串来打印出\n
echo -E #取消反斜杠转义
echo #什么都不打印,就只是换一行
echo -n #不换行输入
cat
#将文件内容打印出来
cat test.txt
cat -n test.txt #打印文件 带行号
cat -b test.txt #打印文件 带行号 不对空白行编号
cat -s test.txt #打印文件 当遇到有连续两行以上的空白行,只显示一行的空白行
#文件清空 >是覆盖 >>是追加
cat /dev/null > test.txt
#写入文本到文件
#注意,如果要写入的文本中包含$,则需要用到转义字符\,否则会被解析变量
#其中EOF可以换成其它的标志,哪怕是AAA,但常用EOF
#EOF之间的内容,要注意格式,因为EOF内是什么内容,到文件中就是什么内容,空格、TAB都会带过去。 结果的EOF前面不能有空格,否则不会被当做结束标志
#如果EOF内还需要套EOF,则可以将里面的EOF换成其它的标志
cat > test.txt<<EOF
第一行文本
第二行文本
\$JAVA_HOME
EOF
mkdir
mkdir /path #创建目录,目录存在会报错
mkdir -p /home/path/path2 #创建目录,如果path不存在,则同时创建。目录存在,则跳过创建
mkdir -p /home/{path,path2} #批量创建目录
touch
touch a.sh #创建一个文件
touch {1..5}.sh #批量创建1.sh ~ 5.sh
grep/whereis/find/sed
这几个命令,使用上要比前面的几个命令要高一级,从查找到替换。
grep
ps -ef | grep java #grep用来做过滤,通常结合管道|来使用,例如查看运行着java的程序的进程都有哪些
grep -e "java" test.txt #过滤出文件中包含 java 的行
grep -e "java" -e "net" test.txt #批量过滤 多个关键字用 -e 来连接
grep "java \| net" test.txt #批量过滤,用|连接,因为有双引号,所有加了\转义
grep -v "java" test.txt #反向过滤,即排除过滤
grep -i "java" test.txt #忽略大小写过滤
grep -n "java" test.txt #过滤时,带行号
grep -c "java" test.txt #过滤出关键字出现的次数
#根据文件内容递归查找目录
grep "java" * #在当前目录搜索带'java'行的文件,*表示不限文件类型,也可以加上一个/多个 --include=*.yml 来限制文件类型
grep -r "java" * #在当前目录及其子目录下搜索'java'行的文件
grep -l -r "java" * #在当前目录及其子目录下搜索'java'行的文件,但是不显示匹配的行,只显示匹配的文件
#查找行首或行尾有指定关键字
grep '^a' test.txt #过滤行首有a的行
grep '$a' test.txt #过滤行尾有a的行 这里因为有$,所以不能用双引号,否则会被当做变量来解析,所以用了单引号
#查找行首是/否英文字母的行
#^ 符号,在字符类符号(括号[])之内与之外是不同的! 在 [] 内代表『反向选择』,在 [] 之外则代表定位在行首的意义!
grep '^[a-zA-Z]' test.txt #开头是英文字母
grep '^[^a-zA-Z]' test.txt #开头不是英文字母
#行尾结束为小数点 (.) 的行
#特别注意到,因为小数点具有其他意义(底下会介绍),所以必须要使用转义字符(\)来加以解除其特殊意义!
grep '\.$' test.txt
grep -v '^$' test.txt #过滤掉空行,例如在查看一些配置文件时,可以把空行过滤掉
whereis
whereis命令只能用于程序名的搜索,而且只搜索二进制文件(参数-b)、man说明文件(参数-m)和源代码文件(参数-s)。如果省略参数,则返回所有信息。
whereis grep #返回所有匹配的结果
grep: /usr/bin/grep /usr/share/man/man1/grep.1.gz
whereis -b grep #返回搜索二进制文件的结果,也就是搜索命令文件
grep: /usr/bin/grep
whereis -m grep #返回说明文件的结果
grep: /usr/share/man/man1/grep.1.gz
find
#语法
find 搜索路径 [选项] 搜索内容
#按照文件名搜索
#-name:按照文件名搜索
find . -name abcde #在当前目录下查找文件名包含 abcde 的文件
#-iname:按照文件名搜索,不区分文件名大小写
find . -iname abcde #在当前目录下查找文件名包含 abcde 的文件, 不区分abcde的大小写
#按照文件类型搜索
#-type f:查找普通文件
find . -type f -name "*.conf" #在当前目录下,查找类型为文件,文件名以.conf结尾的文件
#-type d:查找目录
find . -type d -name "test" #在当前目录下,查找类型为目录,目录名叫test的目录
#其它详细介绍参考 https://zhuanlan.zhihu.com/p/550924132?utm_id=0
需要注意的是,跟find类似的命令,还有要一个locate命令,但该命令查不到最新变动过的文件
sed
前面几个命令基本都在查找,一般我们使用时,都是还牵扯到替换,类似于java当中的replace
# old表示被替换的内容,new表示要替换成的内容
# 其中#也可以换成/或者其它常见的符号,具体换成什么要根本实际的文本来看,例如要替换的文本中包含#则就不能用#
sed 's#old#new#g'
#替换文件中的内容
sed -i 's#old#new#g' test.txt
#删除包含指定内容的行
#以下命令表示删除 test.txt 中,包含 aaa 的所有行
sed -i '/aaa/d' test.txt
#跨行删除,例如将文件中指定开头和结尾的内容删掉
#下面的命令表示将test.txt中,将从#sign_start到#sign_end部分的内容删掉
sed -i "/#sign_start/,/#sign_end/d" test.txt
#批量替换,即批量替换指定目录(及其子目录)中包含指定字符串的文件,可以批量指定文件文件
#其中CONF_FILE_TYPE表示批量指定要扫描的文件类型
#由于sed时可能会报错,因为value可能存在换行等因素,所有为了避免打印出错误信息,特添加了 > /dev/null 2>&1,实际无此需求的话可以不用
#后面的`grep "$KEY" -rl $CONF_FILE_TYPE .`表示批量的检索指定目录(.表示当前目录)下,指定类型的文件中包含指定字符串的所有文件
CONF_FILE_TYPE="--include=*.yml --include=*.yaml "
sed -i "s#$KEY#$VALUE#g" > /dev/null 2>&1 `grep "$KEY" -rl $CONF_FILE_TYPE .`
文件解压缩
tar
#压缩
# -v 表示详细的列出处理的文件,不想看压缩详情,可以去掉该参数
# cvf 打包后为 .tar
# zcvf 打包后为 .tar.gz
# jcvf 打包后为 .tar.bz2
tar czvf test.tar.gz /home/test #将/home/test压缩成 test.tar.gz,解压后会包含/home目录
tar czvf test.tar.gz -C /home test #将/home下的test压缩成 test.tar.gz,解压后不包含/home目录
tar czvf - /home/test | split -b 100m - test.tar.gz #分卷压缩
tar czvf test.tar.gz --exclude=test/logs -C /home test #压缩时,排除test下的logs目录
tar czvf test.tar.gz --exclude=test/logs test #压缩时,排除test下的logs目录
#解压
# xvf 解压 .tar
# zxvf 解压 .tar.gz .tgz
# jxvf 解压 .tar.bz2
tar xzvf test.tar.gz #在当前目录解压该包
tar xzvf test.tar.gz -C /home #将该包解压到 /home 目录
tar xzvf test.tar.gz --strip-components 1 #解压该包时,跳过一层目录。即解压出来后的目录会少掉最上面一层。
zip
#安装zip 系统中默认是不带zip压缩命令的
yum install -y zip
#压缩
zip -r test.zip test #-r表示递归处理,即将test目录下的所有文件及目录及目录中的文件整个压缩,也就是压缩整个文件夹
#zip目前没有找到合适的命令可以在外面路径压缩,例如我在任何路径执行 zip -r test.zip /home/test ,这个时候压缩的包,解压后会有/home路径
zip -r -s 100m test.zip test #-s表示分卷压缩,单位可以是 k千字节,m兆字节,g千兆字节或t万兆字节
#解压
unzip test.zip #解压test.zip这个包
unzip -v test.zip #看看这个包里有什么
unzip -t test.zip #测试这个包能否正确解压
unzip test.zip -d /home #解压包到 /home目录
unzip -o test.zip #解压时覆盖原文件
unzip -n test.zip #解压时不覆盖原文件
#分卷解压
# 要先将分卷合并,然后才能解压
cat test.z* > test.zip
# 根据文件的时间顺序合包
ls -tr test.z* | xargs -i cat {} >> test.zip #其中 -t表示根据时间排序,-r表示倒序
#批量解压
for pack in /home/*.zip; do unzip $pack -d /home; done #批量解压/home下的zip文件,解压到/home目录二
二、进阶命令
防火墙相关
systemctl status firewalld #查询防火墙状态
systemctl stop firewalld #关闭防火墙
systemctl start firewalld #开启防火墙
systemctl disable firewalld #关闭防火墙的开机自启
systemctl enable firewalld #开启防火墙开机自启
firewall-cmd --list-prot #查询防火墙开启的端口号
#开启端口号(操作后要重载防火墙)
firewall-cmd --zone=public --add-port=端口号/tcp --permanent
#批量开启端口号
firewall-cmd --zone=public --add-port=80/tcp --add-port=81/tcp --permanent
firewall-cmd --zone=public --add-port=80~90/tcp --permanent
firewall-cmd --reload #重载防火墙
#关闭端口(操作后要重载防火墙)
firewall-cmd --zone=public --remove-port=端口号/tcp --permanent
#判断防火墙状态
FIREWALL_STATE=$(firewall-cmd --state)
if [ "$FIREWALL_STATE" == "running" ]; then
echo ">>> Firewall Is Running !!!"
fi
#判断端口号是否已开通
TEST_PORT=$(firewall-cmd --list-port |grep "端口号/tcp")
if [ "$TEST_PORT" == "" ]; then
echo "端口号未开通"
fi
网络命令
netstat
#安装工具包
yum install -y net-tools
#查询端口监听情况
netstat -anp
#获取nginx监听的端口号
netstat -anp | grep nginx |grep tcp | grep master | grep -v tcp6|awk '{print Ŭ}'|cut -d ":" -f2 | sort | uniq
#根据nginx监听的端口号来进行防火墙端口开放实例
FIREWALL_STATE=$(firewall-cmd --state)
if [ "$FIREWALL_STATE" == "running" ]; then
echo ">>> 防火墙开启中,执行开放端口 !!!"
PORTS=$(netstat -anp | grep nginx |grep tcp | grep master | grep -v tcp6|awk '{print Ŭ}'|cut -d ":" -f2)
PORT_ARR=(`echo $PORTS | tr ' ' ' '`)
#可能存在只有一个端口开放,这个时候array是空
if [ "$PORTS" == "" ]; then
echo "nginx可能启动失败了,没有检测到其监听的端口"
exit 1
fi
if [ "$PORT_ARR" == "" ]; then
#说明只开了一个端口
TEST_PORT=$(firewall-cmd --list-port |grep "$PORTS/tcp")
if [ "$TEST_PORT" == "" ]; then
echo "开放端口号:$PORTS"
firewall-cmd --zone=public --add-port=$PORTS/tcp --permanen
fi
else
for i in "${!PORT_ARR[@]}"; do
PORT=${PORT_ARR[i]}
TEST_PORT=$(firewall-cmd --list-port |grep "$PORT/tcp")
if [ "$TEST_PORT" == "" ]; then
echo "开放端口号:$PORT"
firewall-cmd --zone=public --add-port=$PORT/tcp --permanen
fi
done
fi
#重载防火墙配置
echo "重载防火墙"
firewall-cmd --reload
fi
#获取所有对外监听的tcp端口号,其中过滤掉tcp6(即ipv6)的,22 3344这两个端口,并且从小到大排序,有兴趣的可以逐步加管道去执行看看各自的结果
netstat -anp | grep tcp | grep -v tcp6 | grep LISTEN | grep -v '127.0.0.1' | awk '{print Ŭ}' | cut -d ':' -f2 | grep -v 22 | grep -v 3344 | sort | uniq
curl
#通过curl来判断url是否通
#-I 表示获取head信息
#-m 表示超时时间,单位:秒,即多久后超时,
#-s 表示silent模式,即不展示请求过程状态
#-o 表示将结果输出到/dev/null中,否则会打印出获取的head信息
#-w 用于在一次完整且成功的操作后输出指定格式的内容到标准输出。输出格式由普通字符串和任意数量的变量组成,输出变量需要按照%{variable_name}的格式
#http_code表示要获取状态码,Url不通时,返回的是000,其它的都表示这个url是通的,即存在的
curl -I -m 1 -s -o /dev/null -w %{http_code} http://baiduuuu.com/
#通过curl发送get请求并带参数,其中 -H表示要给header传参,--data表示要提交的表单数据
curl "http://127.0.0.1:8848/nacos/v1/cs/configs?&accessToken=SecretKey012345678901234567890123456789012345678901234567890123456789" -H 'Content-Type: application/x-www-form-urlencoded' --data "dataId=1&group=1&type=1&content=1&tenant=1&namespaceId=1"
#通过curl发送post请求并带参数 -H表示要给header传参,-X表示定义请求方式, -d表示请求的数据体,也就是Body
curl -H "Content-Type: application/json" -X POST -d '{"user_id": "123", "coin":100, "success":1, "msg":"OK!" }' "http://192.168.0.1:8001/test"
wget
#安装工具包
yum install -y wget
#下载文件到当前目录
wget https://cn.wordpress.org/wordpress-4.9.4-zh_CN.tar.gz
#在后台下载文件到当前目录
wget -b https://cn.wordpress.org/wordpress-4.9.4-zh_CN.tar.gz
#批量下载,即将要下载的url都写入filelist.txt中,一行是一个url
wget -i filelist.txt
#下载到指定目录
wget -P /home/test https://cn.wordpress.org/wordpress-4.9.4-zh_CN.tar.gz
#下载到指定目录并重命名
wget -O /home/test/abc.tar.gz https://cn.wordpress.org/wordpress-4.9.4-zh_CN.tar.gz
#更多用法请参考 https://blog.csdn.net/qq_45594628/article/details/134041117
nc
我经常的用法是用它来检测端口
#通过nc来判断 默认是TCP,需要UDP,则需要加上-u,具体参考nc命令详解
#安装nc
yum install -y nc
#简单测试看结果,-v表示输出详细信息
nc -v 39.105.162.80 8000
#nc使用实例 检测端口是否通
#-v表示输出详细信息
#-z表示告诉netcat使用0 IO,连接成功后立即关闭连接,不进行数据交换
#-w表示连接和最终网络读取超时
#2>&1表示将原本输出到stderr中的内容重定向输出到stdout,这样就可以拿到内容处理,类似取jdk版本号时如果想解析java -version返回的内容,也需要做此操作才能传给管道
#wc -l 表示统计行数,也就是统计下nc返回的结果中,有没有出现"No route to host"或者"Connection refused"的,有的话就表示失败了
result=$(nc -v -z -w 5 IP PORT 2>&1|grep -e "No route to host" -e "Connection refused"|wc -l)
if [ $result == 0 ];then
echo "Success"
else
echo "Fail"
fi
日常排查问题
日常排查问题时,我用的最多的几个命令基本就这几个 ps/top/wc/cut/awk/sort/uniq
ps
# ps命令用来列出系统中当前运行的那些进程(静态查看,如果想看动态的进程情况,可以使用下面的top)
-A #显示所有程序。与 -e 具有同样的效用。
-e #此选项的效果和指定"A"选项相同。
-f #显示UID,PPIP,C与STIME栏位。
a #显示现行终端机下的所有程序,包括其他用户的程序。
u #以用户为主的格式来显示程序状况。
x #显示所有程序,不以终端机来区分。
#最常用的两个组合
ps aux #是用BSD的格式来显示
[root@euler-his ~]# ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 166376 12908 ? Ss 11:05 0:01 /usr/lib/systemd/systemd --switched-root --system --deserialize 16
root 2 0.0 0.0 0 0 ? S 11:05 0:00 [kthreadd]
root 3 0.0 0.0 0 0 ? I< 11:05 0:00 [rcu_gp]
root 4 0.0 0.0 0 0 ? I< 11:05 0:00 [rcu_par_gp]
root 6 0.0 0.0 0 0 ? I< 11:05 0:00 [kworker/0:0H-kblockd]
root 8 0.0 0.0 0 0 ? I< 11:05 0:00 [mm_percpu_wq]
root 9 0.0 0.0 0 0 ? S 11:05 0:00 [rcu_tasks_rude_]
ps -ef #标准的格式显示进程的
[root@euler-his ~]# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 11:05 ? 00:00:01 /usr/lib/systemd/systemd --switched-root --system --deserialize 16
root 2 0 0 11:05 ? 00:00:00 [kthreadd]
root 3 2 0 11:05 ? 00:00:00 [rcu_gp]
root 4 2 0 11:05 ? 00:00:00 [rcu_par_gp]
root 6 2 0 11:05 ? 00:00:00 [kworker/0:0H-kblockd]
root 8 2 0 11:05 ? 00:00:00 [mm_percpu_wq]
root 9 2 0 11:05 ? 00:00:00 [rcu_tasks_rude_]
root 10 2 0 11:05 ? 00:00:00 [rcu_tasks_trace]
top
#top命令可以动态的显示进程的状况,我一般在查看某个进程的状态,例如CPU使用情况、内存使用情况时,会使用该命令
top - 17:33:23 up 6:28, 1 user, load average: 0.00, 0.00, 0.00
Tasks: 235 total, 1 running, 234 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
MiB Mem : 79923.8 total, 78827.7 free, 1015.8 used, 815.2 buff/cache
MiB Swap: 4096.0 total, 4096.0 free, 0.0 used. 78908.0 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 166376 12908 8628 S 0.0 0.0 0:01.33 systemd
2 root 20 0 0 0 0 S 0.0 0.0 0:00.01 kthreadd
3 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 rcu_gp
4 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 rcu_par_gp
6 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 kworker/0:0H-kblockd
8 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 mm_percpu_wq
9 root 20 0 0 0 0 S 0.0 0.0 0:00.00 rcu_tasks_rude_
10 root 20 0 0 0 0 S 0.0 0.0 0:00.00 rcu_tasks_trace
#有时为了方便截图,可以将变化时间间隔设置大一些,可以加上-d参数
top -d 10 #表示10秒刷新一次
#如果只想观察某个进行的变化,可以指定进程号
top -p<进程号>
#有时排查问题时,需要查看具体目录,这个时候可以在top中按 c 来显示路径
top - 17:38:36 up 6:33, 1 user, load average: 0.00, 0.00, 0.00
Tasks: 235 total, 1 running, 234 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
MiB Mem : 79923.8 total, 78828.4 free, 1015.1 used, 815.2 buff/cache
MiB Swap: 4096.0 total, 4096.0 free, 0.0 used. 78908.7 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
2695 root 20 0 26860 5900 3704 R 100.0 0.0 0:00.01 top -d 10
1 root 20 0 166376 12908 8628 S 0.0 0.0 0:01.33 /usr/lib/systemd/systemd --switched-root --system --deserialize 16
2 root 20 0 0 0 0 S 0.0 0.0 0:00.01 [kthreadd]
3 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 [rcu_gp]
#在top中,还可以使用如下命令辅助排查问题
M #根据内存大小排序
P #根据CPU使用率排序(默认是该排序)
wc
# wc命令一般作为组合使用,用来统计行数、字数和字节数
-c #统计字节数
[root@localhost ~]# ll
总用量 72040
-rw-------. 1 root root 1555 1月 17 2023 anaconda-ks.cfg
drwxr-xr-x. 3 root root 19 6月 7 14:01 data
-rw-r--r--. 1 root root 73759281 6月 7 10:57 docker-26.1.4.tgz
-rw-r--r--. 1 root root 814 6月 7 16:11 docker-compose.yml
[root@localhost ~]# wc -c docker-compose.yml
814 docker-compose.yml
-l #统计行数
[root@localhost ~]# wc -l docker-compose.yml
31 docker-compose.yml
-w #统计字数
[root@localhost ~]# wc -w docker-compose.yml
59 docker-compose.yml
-L #统计最长行的长度
[root@localhost ~]# wc -L docker-compose.yml
68 docker-compose.yml
#组合使用,查询有多少java关键字的进程
ps -ef|grep java|grep -v grep |wc -l #其中grep -v grep是为了过滤掉grep进程
[root@localhost ~]# ps -ef|grep java|grep -v grep |wc -l
0
cut
-b #(--bytes): 按字节位置提取。例如,-b 1-3 表示提取每行的第 1 到第 3 个字节。
-c #(--characters): 按字符位置提取。与 -b 类似,但是在多字节字符环境中,它会以字符为单位进行计数。
-f #(--fields): 按字段提取。字段是由分隔符(默认为制表符)分隔的文本单元。例如,-f 1,3 表示提取每行的第 1 和第 3 个字段。
-d #(--delimiter): 指定字段分隔符。默认情况下,字段由制表符分隔。例如,-d ',' 会将逗号作为字段分隔符。
--complement #补充模式。提取未被 -b, -c, 或 -f 选项指定的部分,即反向提取。
#例如有一个文本data.txt内容如下(#号是为了注释,文本中实际没有#):
#Name,Age,Gender
#Alice,30,Female
#Bob,25,Male
#要提取第二列(年龄),可以使用以下命令:
cut -d ',' -f 2 data.txt
#其中 -d ','表示按照后面逗号作为分隔符, -f 2 表示要提取第二列
awk
#AWK 是一种处理文本文件的语言,是一个强大的文本分析工具,在处理文本方面属于三剑客之一(grep、sed、awk),其中
grep #过滤文本
sed #修改文本
awk #处理文本
#在实际使用中,awk主要用来格式化,功能过于强大,这里我们只做简单介绍,以辅助日常使用
print #打印
NF #统计总字段数
$ #取值
#例如有如下文本demo.txt
[root@localhost ~]# cat demo.txt
aa ad ac
asd sedf qwe
aa wd
qq
vv dd
[root@localhost ~]# awk '{print NF}' demo.txt
3
3
2
1
2
# 其中NF表示每行的字段数, print表示打印出来
[root@localhost ~]# awk '{print $NF}' demo.txt
ac
qwe
wd
qq
dd
#上述命令表示,首先NF是统计每行字段数,加上$之后,就变成了取值,例如第一行NF是3,则相当于ū,$NF就是取第三个字段的值,然后print打印出来
sort
#sort 命令用于将文本文件内容加以排序,可针对文本文件的内容,以行为单位来排序.
-b #忽略每行前面开始出的空格字符。
-c #检查文件是否已经按照顺序排序。
-d #排序时,处理英文字母、数字及空格字符外,忽略其他的字符。
-f #排序时,将小写字母视为大写字母。
-i #排序时,除了040至176之间的ASCII字符外,忽略其他的字符。
-m #将几个排序好的文件进行合并。
-M #将前面3个字母依照月份的缩写进行排序。
-n #依照数值的大小排序。
-u #意味着是唯一的(unique),输出的结果是去完重了的。
-o<输出文件> #将排序后的结果存入指定的文件。
-r #以相反的顺序来排序。
-t<分隔字符> #指定排序时所用的栏位分隔字符。
+<起始栏位>-<结束栏位> #以指定的栏位来排序,范围由起始栏位到结束栏位的前一栏位。
[-k field1[,field2]] #按指定的列进行排序。
#一般使用时,可以结合前面的命令,来对结果进行排序,以便展示排查问题
uniq
#该命令通常用进行去重使用。
#例如有如下文本demo.txt:
test 30
test 30
test 30
Hello 95
Hello 95
Hello 95
Hello 95
Linux 85
Linux 85
uniq demo.txt:
test 30
Hello 95
Linux 85
# 注意!!!! 当重复的行并不相邻时,uniq 命令是不起作用的
# 所以这个时候就需要结合sort命令,先进行排序,然后在uniq去重,例如:
sort demo.txt | uniq
#其它扩展命令
-c #在每列旁边显示该行重复出现的次数。
-d #仅显示重复出现的行列。
-f<栏位> #忽略比较指定的栏位。
-s<字符位置> #忽略比较指定的字符。
-u #仅显示出一次的行列。
-w<字符位置> #指定要比较的字符。