当前位置: 首页 > news >正文

重定向、命令行判断、管道、正则三剑客

文章目录

  • 特殊符号
  • 数据流重定向
    • 输出重定向
    • 输入重定向
  • 命令执行的判断根据:;、&&、||
  • 管道命令(pipe)
    • 选取命令:cut、grep
    • 排序命令:sort、wc、uniq
    • 双向重定向:tee
    • 字符转换命令:tr、col、join、paste、expand
    • 划分命令:split
    • 参数代码:xargs
    • 关于减号【-】的用途
  • 正则表达式是什么
    • grep(擅长查找功能)
      • grep配合基本正则表达式案例
      • grep配合扩展正则表达式案例
    • sed(擅长取行和替换)
    • awk(擅长取列)
      • awk常见用法
      • awk自定义变量
      • awk的逻辑运算字符
      • printf格式化输出
      • echo 和printf区别

特殊符号

引号类型解析变量($var解析命令($(cmd)解析通配符(*典型用途
反引号 ` (优先执行)无(自身是命令替换)优先执行并替换结果不解析命令结果嵌入和 $(...)相同
单引号 '不解析不解析不解析原样输出特殊字符
双引号 "解析解析不解析保留格式并解析变量
不加引号解析解析解析自动分词或扩展通配符
[root@ubt2404csq ~]# echo "123 `whoami` $(pwd) csq{01..5}"
123 root /root csq{01..5}
[root@ubt2404csq ~]# echo '123 `whoami` $(pwd) csq{01..5}'
123 `whoami` $(pwd) csq{01..5}
[root@ubt2404csq ~]# echo 123 `whoami` $(pwd) csq{01..5}
123 root /root csq01 csq02 csq03 csq04 csq05

数据流重定向

数据流重定向是指将命令执行后本应输出到屏幕的数据,定向传输到文件、设备或其他位置

什么是数据流重定向

什么是数据流重定向呢?这得由命令的执行说起,一般来说,如果你要执行一个命令,通常它会是这样的:

image-20230425092132828

数据流名称文件描述符(FD)默认方向作用说明
标准输入0键盘命令从这里读取输入数据
标准输出1终端(屏幕)命令的正常执行结果输出到这里
标准错误输出2终端(屏幕)命令的错误信息(如报错)输出到这里

我们执行一个命令的时候,这个命令可能会由文件读入数据,经过处理之后,再将数据输出到屏幕上。

输出重定向

基本输输出重定向:>与>>

针对 标准输出,默认可省略文件描述符 1

符号语法格式作用说明
>command > file将命令的 stdout 重定向到 file覆盖文件原有内容(若文件不存在则创建)
>>command >> file将命令的 stdout 重定向到 file追加到文件末尾(若文件不存在则创建)
  1. 覆盖写入文件
# 将 "Hello Linux" 覆盖写入 test.txt(原内容会丢失)
echo "Hello Linux" > test.txt# 查看结果
cat test.txt  # 输出:Hello Linux
  1. 追加写入文件
# 将 "I love Redirection" 追加到 test.txt 末尾
echo "I love Redirection" >> test.txt# 查看结果
cat test.txt  
# 输出:
# Hello Linux
# I love Redirection

错误输出重定向:2>与2>>

针对 标准错误输出,必须显式指定文件描述符 2

符号语法格式作用说明
2>command 2> error.log将命令的 stderr 重定向到 error.log覆盖原有内容
2>>command 2>> error.log将命令的 stderr 重定向到 error.log追加到末尾
  1. 捕获错误信息
# 尝试读取不存在的文件,错误信息会输出到屏幕
cat no_such_file.txt  # 输出:cat: no_such_file.txt: No such file or directory# 将错误信息捕获到 error.log
cat no_such_file.txt 2> error.log# 查看错误日志
cat error.log  # 输出:cat: no_such_file.txt: No such file or directory

合并输出:stdout + stderr 重定向到同一文件

「正常结果」和「错误信息」保存到同一个文件

符号组合语法格式作用说明
2>&1command > combined.log 2>&1先将 stdout 重定向到文件,再将 stderr 「复制」stdout 的方向(覆盖)
&>command &> combined.log将 stdout(1)和 stderr(2)同时重定向combined.log(覆盖)
  1. 将错误和正确的消息都输出到垃圾桶
# 安装软件时屏蔽所有输出(不看进度和提示)
apt update > /dev/null 2>&1

输入重定向

输入重定向用于改变命令的「输入来源」,从默认的「键盘」改为「文件」或「字符串」

基本输入重定向:<

针对 标准输入,默认可省略文件描述符 0

  1. 利用cat命令来建立一个文件的简单流程
[csq@localhost ~]$ cat > catfile
I like Linux
but I don't like English
<== 这里按下ctrl + d 来退出
[csq@localhost ~]$ cat catfile 
I like Linux
but I don't like Englisht
  1. 用stdin替换键盘的输入以建立新文件的简单流程
[csq@localhost ~]$ cat > catfile < ~/.bashrc 
[csq@localhost ~]$ ll catfile ~/.bashrc 
-rw-rw-r--. 1 csq csq 231 Apr 25 15:13 catfile
-rw-r--r--. 1 csq csq 231 Apr  1  2020 /home/csq/.bashrc
# 可以看到两个文件大小一模一样,可以自行查看一下内容也是一模一样的

基本输入追加重定向:<<

<< 允许你在命令行中直接输入多行文本作为命令的 stdin,无需单独创建文件,语法为

命令 << 分隔符
多行文本内容
EOF
# 注意:若分隔符单引号(如 << 'EOF'),则多行文本中的变量、命令不会被解析
# 不加引号则会解析
  1. 生成多行文件
cat  > poem.txt << EOF
床前明月光,
疑是地上霜。
举头望明月,
低头思故乡。
EOF
  1. 解析变量
#1.单引号不能解析变量(常用于写入yum.repo文件)
[root@kylin-v10-sp3-csq ~]# home=/root
[root@kylin-v10-sp3-csq ~]# cat << 'EOF'
> echo $home
> EOF
echo $home
#2.去除单引号即可解析变量(常用于编写脚本,可以避免使用大量echo)
[root@kylin-v10-sp3-csq ~]# cat << EOF 
echo $home
EOF
echo /root

命令执行的判断根据:;、&&、||

在某些情况下,我想要一次执行很多命令,而不想分次执行时,该怎么办?基本上你有两种选择,一个是通过shell脚本去执行,一种则是通过下面的介绍来输入多个命令。

cmd ; cmd(不考虑命令相关性的连续命令执行)

在某些时候,我们希望可以一次执行多个命令,例如关机的时候我希望可以执行两次 sync同步写入磁盘后才shutdown计算机,那么可以怎么做呢?

[root@localhost ~]# sync ; sync ; shutdown -h now

在命令与命令中间利用分号【;】开隔开,这样一来,分号前的命令执行完后就立刻接着执行后面的命令。

那么我如果想在某个目录下面建一个文件,也就是说,如果该目录存在的话,那我才建立文件,如果不存在,那就不创建文件。也就是说这两个命令彼此之间是由相关性的,前一个命令是否成功执行与后一个命令要是否执行有关,那就要用&&或||

$?(命令返回值)与&&或||

如同上面谈到的,两个命令之间有依赖性,而这个依赖性主要判断的地方就在于前面一个命令的执行结果是否正确。判断原理就是【若前面一个命令执行结果正确,在Linux下面就会返回一个$?=0的值】

命令执行情况说明
cmd1 && cmd21. 若cmd1 执行完毕且正确执行($?=0),则开始执行cmd2
2. 若cmd1 执行完毕且为错误($?≠0),则cmd2不执行
cmd1 || cmd21. 若cmd1 执行完毕且正确执行($?=0),则cmd2 不执行
2. 若cmd1 执行完毕且为错误($?≠0),则开始执行cmd2

上述cmd1 及 cmd2 都是命令。

# 示例1 使用ls 查看目录/tmp/abc是否存在,若存在则用touch 建立/tmp/abc/heh
[root@localhost ~]# ls /tmp/abc/ && touch /tmp/abc/hehe
ls: cannot access /tmp/abc/: No such file or directory
# ls说无法访问/tmp/abc/: 没有那个文件或目录,并没有touch的错误,表示touch并没有执行。
[root@localhost ~]# mkdir /tmp/abc
[root@localhost ~]# ls /tmp/abc/ && touch /tmp/abc/hehe
[root@localhost ~]# ll /tmp/abc/hehe 
-rw-r--r--. 1 root root 0 Apr 25 16:20 /tmp/abc/hehe# 示例2 看到了吧,/tmp/abc不存在,touch就不会执行,若/tmp/abc存在的话,
# 那么touch就会开始执行。不过这样非常麻烦!能不能自动判断,如果没有该目录就自己建立一个
[root@localhost ~]# rm -rf /tmp/abc/           # 先删除此目录方便测试
[root@localhost ~]# ls /tmp/abc || mkdir /tmp/abc
ls: cannot access /tmp/abc: No such file or directory    # ls报错没有/tmp/abc
[root@localhost ~]# ll -d /tmp/abc
drwxr-xr-x. 2 root root 6 Apr 25 16:23 /tmp/abc          # mkdir创建了# 示例3 如果你再重复执行【ls  /tmp/abc || mkdir /tmp/abc】也不会出现重复mkdir的错误,
# 这是因为/tmp/abc已经存在了,后续的mkdir 就不会执行。
# 如果我想要建立/tmp/abc/hehe这个文件,但我不知道/tmp/abc是否存在,那该如何是好?
[root@localhost ~]# ls /tmp/abc || mkdir /tmp/abc && touch /tmp/abc/hehe

上述案例种尝试建立/tmp/abc/hehe,不管/tmp/abc 是否存在。那么案例三应该如何解释?由于Linux下面的命令都是由左向右执行,所以说上述案例有几种情况来分析一下:

  • (1) 若/tmp/abc 不存在故返回 $?≠0,则 (2) 因为 || 遇到非为 0 的$?故开始 mkdir /tmp/abc ,由于mkdir /tmp/abc 会成功执行,所以返回 $?=0 (3) 遇到$?=0 故会执行 touch /tmp/abc/hehe 最终hehe被建立

  • (2) 若/tmp/abc存在故返回 $?=0 则(2) 因为|| 遇到0的$?不会执行,此时 $?=0继续向后传,故(3)因为遇到$?=0 开始建立 /tmp/abc/hehe 了,最终 /tmp/abc/hehe 被建立

整个流程图如下:

image-20230425165939877

上面这张图的两股数据种,上方的线程为不存在 /tmp/abc 时所进行的命令操作,下方的线段则是存在 /tmp/abc 的命令操作。

# 以ls 测试/tmp/csq 是否存在,若存在则显示 "yes" 不存在则显示 "no"
[root@chenshiren ~]# ls /tmp/csq  >/dev/null  2>&1 && echo "yes" || echo "no"
no

练习到这里你应该知道了,命令是一个接着一个去执行的,因此,如果真的使用判断,那么整个 && 与 || 的顺序不能搞错。一般来说,假设判断式有三个,也就是:

command1 && command2 || command3

一般来说 command2 和command3 会使用肯定可以执行的成功的命令。

管道命令(pipe)

有时候我在bash命令执行输出数据的时候,有时候数据必须要经过好几个命令处理后才能得到我们想要的结果。这时候我们就可以时候管道命令,管道命令使用的是【|】这个符号shift + \即可输出。我们来利用管道命令简单的举个例子

假设我们想要知道/etc/下面有多少文件,那么可以利用【 ls /etc】 来查看,不过,因为/etc 下面文件太多了,导致输出以后屏幕很多内容,此时我们可以通过 less命令的协助

[root@localhost ~]# ls /etc/ | less

如此一来,使用ls命令输出后的内容,就能够被less读取,并且利用less功能,我们就可以前后翻动或者/file 查找文件,非常方便。其实这个管道命令【|】仅能处理前一个命令传来的正确信息,也就是标准输出信息,对于标准错误信息并没有直接处理能力。

管道命令处理流程图如下所示

image-20230426090721994

如上图所示,每个管道后面接的第一个数据必定是【命令】,而且这个命令必须能够接受标准输入的数据才行,这样的命令才可为管道命令,如less、more、head、tail 等都是可以接受标准输入的管道命令至于例如 ls、cp、mv等就不是管道命令。因为ls、cp、mv并不会接受来自stdin的数据,也就是说,管道命令主要有两个比较特殊的地方:

  • 管道命令仅会处理标准输出,对于标准错误输出会给予忽略
  • 管道命令必须要能够接受来自前一个命令的数据成为标准输入继续处理才行。

如果你硬是要让标准错误可以被管道命令所使用的话,可以这么做。可以使用数据流重定向,让2>&1加入命令中,就可以让2> 变成1>。

选取命令:cut、grep

什么是选取命令?就是将一段数据经过分析后,取出我们所想要的,或是经由分析关键词,取得我们所想要的那一行。不过,要注意的是,一般来说,选取信息通常是针对【一行一行】来分析的,并不是整篇信息分析,下面介绍两个很常用的信息选取命令

cut

cut翻译成英格利希的意思就是【切】,这个命令可以将一段信息的某一段给他【切】出来,处理的信息就是以【行】为单位

cut -d '分隔字符' -f 字段
cut -c 字符区间
选项:
-d:后面接分隔字符,与-f一起使用
-f:根据-d分隔字符将一段信息划分成为数段,用-f取出第几段的意思
-c:以字符的单位取出固定字符的区间# 示例1 将PATH变量取出,我要找出第五个路径
[root@localhost ~]# echo ${PATH}
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin1               2           3        4        5
[root@localhost ~]# echo ${PATH} | cut -d ':' -f 5
/root/bin
# 如同上面数字显示,我们是以【:】作为分隔,因此会出现/root/bin# 示例2 如果想要列出第3和第5,可以这样
[root@localhost ~]# echo ${PATH} | cut -d ':' -f 3,5
/usr/sbin:/root/bin# 示例3 将export输出的信息,取得第12字符以后的所有字符
[root@localhost ~]# export
declare -x HISTCONTROL="ignoredups"
declare -x HISTSIZE="1000"
declare -x HOME="/root"
declare -x HOSTNAME="localhost.localdomain"
declare -x LANG="zh_CN.UTF-8"
declare -x LESSOPEN="||/usr/bin/lesspipe.sh %s"
declare -x LOGNAME="root"
.....
.......
...
# 注意看,每个数据都是整齐的输出,如果我们不想要【declare -x 】时,就得这样做
[root@localhost ~]# export | cut -c 12-
HISTCONTROL="ignoredups"
HISTSIZE="1000"
HOME="/root"
HOSTNAME="localhost.localdomain"
LANG="zh_CN.UTF-8"
LESSOPEN="||/usr/bin/lesspipe.sh %s"
LOGNAME="root"
...........
......
...# 示例4 用last将显示的登录者的信息中,仅留下使用者的大名
[root@localhost ~]# last
root     pts/1        192.168.100.1    Wed Apr 26 08:42   still logged in   
root     pts/0        192.168.100.1    Wed Apr 26 08:42   still logged in   
root     pts/1        192.168.100.1    Tue Apr 25 15:54 - 18:56  (03:01)    
root     pts/0        192.168.100.1    Tue Apr 25 15:54 - 18:56  (03:01)    
reboot   system boot  3.10.0-1160.el7. Tue Apr 25 15:51 - 09:37  (17:45)  
.....
.......
...
# last 可以输出【账号/终端/来源/日期时间】的数据,并且是排列整齐的。
[root@localhost ~]# last | cut -d ' ' -f 1
root
root
root
root
reboot
root
root
.....
.......
...
# 由输出的结果我们可以发现第一个空白分隔的栏位代表账号,所以使用如上命令
# 但是因为root   pts/1 之间空格有好几个,并非仅有一个,所以,如果要找出
# pts1/1 其实不能以 cut -d ' ' -f 1,2   输出结果会不是我们想要的

grep

grep命令将会在下面的内容中介绍

排序命令:sort、wc、uniq

很多时候,我们都会区计算一次数据里面的相同形式的数据总数,举例来说,使用last可以查得系统上面有登录主机者的身份。那么我可以针对每个用户查出它们的总登录次数吗?此时就要排序与计算之类的命令来辅助,下面介绍一下几个好用的排序与统计的命令。

sort

sort它可以帮我们进行排序,而且可以根据不同的数据形式来排序,例如数字与文字的排序就不一样。

sort  [-fbMnrtuk] [file   或  stdin]
选项:
-f:忽略大小写的差异,例如A与a视为编码相同
-b:忽略最前面的空格字符部分
-M:以月份的名字来排序,例如JAN、DEC等排序方法
-n:使用【纯数字】进行排序(默认是以文字形式来排序的)
-r:反向排序
-u:就是uniq,相同的数据中,仅出现一行代表。
-t:分隔符号,默认是使用[TAB]键来分隔
-k:以哪个区间来进行排序的意思。
-h:以人类可读的方式排序# 示例1 个人账号都记录在/etc/passwd下,请将账号进行排序
[root@localhost ~]# cat /etc/passwd | sort
adm:x:3:4:adm:/var/adm:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
chrony:x:998:996::/var/lib/chrony:/sbin/nologin
csq:x:1000:1000::/home/csq:/bin/bash
daemon:x:2:2:daemon:/sbin:/sbin/nologin
.....
...
# 直接输入sort 默认是以【文字】形式来排序的,所以由a开始排序到最后# 示例2 /etc/passwd内容是以【:】分隔的,我想以第三栏来排序,该如何?
[root@localhost ~]# cat /etc/passwd | sort -t ':' -k  3   
root:x:0:0:root:/root:/bin/bash
csq:x:1000:1000::/home/csq:/bin/bash
zhw:x:1001:1001::/home/zhw:/bin/bash
zzh:x:1002:1002::/home/zzh:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
....
......
..
# 发现了吗sort默认是以文字形式来排序的,如果想要数字排序
# cat /etc/passwd | sort -t ':' -k  3 -n 这样才行 加上-n来告知sort是以数字来排序# 示例3 利用last,将输出的数据仅显示账号,并加以排序
[root@localhost ~]# last | cut -d ' ' -f 1 | sort   
# 示例4 查找系统中最大的文件
du -sh /* 2>/dev/null | sort -rnk1
#然后一级一级查找直到查到最大的文件

uniq

如果我完成了排序,我想要将重复的数据仅列出一个显示,可以怎么做呢?

uniq [-ic]
选项:
-i:忽略大小写字符的不同
-c:进行计数# 示例1 使用last将账号列出,仅取出账号栏,进行排序后,仅取出一位
[root@localhost ~]# last | cut -d ' ' -f 1 | sort | uniq   reboot
root
wtmp# 示例2 如果我还想要知道每个人登录的总次数呢?
[root@localhost ~]# last | cut -d ' ' -f 1 | sort | uniq -c1 7 reboot34 root1 wtmp
# 1.先将所有的数据列出来 2.再将人名独立出来 3.经过排序 4.只显示一个
# 从上述案例得知可以发现reboot出现了7次,root登录则有34次,大部分都是root在登录
# wtmp与第一行的空白都是last的默认字符,两个可以忽略

这个命令用来将重复的行删除掉只显示一个,举例来说,你要知道这个月登录你主机的用户有谁,而不在乎它的登录次数,那么就可以使用上面的案例。

wc

如果我想知道/etc/man_db.conf 这个文件里面有多少文字?多少行?多少字符?,可以利用wc这个命令来完成,它可以帮我们计算出信息的整体数据

wc [-lwm]
选项:
-l:仅列出行
-w:仅列出多少字
-m:多少字符# 示例1 man_db.conf里面到底有多少行、字数、字符数呢?
[root@localhost ~]# cat /etc/man_db.conf | wc131     723    5171
# 输出的三个数字中,分别代表:【行、字数、字符数】# 示例2 使用last可以输出登录者,但是last最后两行并非账号内容,
# 那么请问,我该如何以一行命令串取得登录系统的总人次呢?
[root@localhost ~]# last |grep [a-zA-z] |grep -v 'wtmp' | grep -v 'reboot' | wc -l
34# 由于last会输出空白行,wtmp、reboot等无关账号登录的信息
# 因此,利用grep 取出非空白行,以及取出上述关键字的那几行,在计算行数,就好了

双向重定向:tee

前面我们了解过数据流重定向知道【>】会将数据流整个传送给文件或设备,因此我们除非去读取该文件或设备,否则就无法继续利用整个数据流。那如果我想要将整个数据流处理过程中将某段信息存下来,应该怎么做呢?利用tee就行

image-20230426145646442

tee会同时将数据流分送到文件与屏幕,而输出到屏幕,其实是stdout,那就可以让下个命令继续处理

tee [-a] file
选项:
-a:以累加的方式,将数据加入file当中# 示例1 将last输出存一份到last.list文件中
[root@localhost ~]# last | tee last.list | cut -d " " -f 1
root
root
root
root
......
...# 示例2 将ls -l /home 的数据存一份到~/homefile,同时屏幕也有输出信息
[root@localhost ~]# ls -l /home | tee ~/homefile      
total 0
drwx------. 2 csq csq 162 Apr 25 14:48 csq
drwx------. 2 zhw zhw  62 Apr 25 09:52 zhw
drwx------. 2 zzh zzh  62 Apr 25 09:52 zzh
# 如果信息很多的话在后面可以加一个【 | less】# 示例3 再ls -l /etc的数据累加到~/homefile中,同时屏幕也要输出信息
[root@localhost ~]# ls -l /etc/ | tee -a ~/homefile | less
# 是否累加成功可以自行查看

字符转换命令:tr、col、join、paste、expand

tr

可以用来删除一段信息当中的文件,或是进行文字信息的替换

tr [-ds] SET1 ....
选项:
-d:删除信息当中的SET1字符
-s:替换掉重复的字符# 示例1 将last输出的信息中,所有的小写变成大写字符
[root@localhost ~]# last | tr '[a-z]' '[A-Z]'
ROOT     PTS/1        192.168.100.1    WED APR 26 09:42   STILL LOGGED IN   
ROOT     PTS/0        192.168.100.1    WED APR 26 09:42   STILL LOGGED IN  
.....
...# 示例2 将/etc/passwd 输出信息中,将冒号【:】删除
[root@localhost ~]# cat /etc/passwd | tr -d ':'
rootx00root/root/bin/bash
binx11bin/bin/sbin/nologin
daemonx22daemon/sbin/sbin/nologin
admx34adm/var/adm/sbin/nologin
.....
...# 示例3 将/etc/passwd转成dos换行到/root/passwd中,再将^M符号删除
[root@localhost ~]# cp -rf /etc/passwd  ~/passwd && unix2dos ~/passwd
unix2dos: converting file /root/passwd to DOS format ...
[root@localhost ~]# file ~/passwd 
/root/passwd: ASCII text, with CRLF line terminators   # 这就是DOS换行
[root@localhost ~]# cat  ~/passwd | tr -d '\r' > ~/passwd.Linux
[root@localhost ~]# ll /etc/passwd ~/passwd*
-rw-r--r--. 1 root root 957 Apr 25 09:52 /etc/passwd
-rw-r--r--. 1 root root 979 Apr 26 15:12 /root/passwd
-rw-r--r--. 1 root root 957 Apr 26 15:12 /root/passwd.Linux
# 处理过后,发现文件大小与原本的/etc/passwd就一致了

上述案例,为什么可以使用\r替换?

回车符(Carriage Return)或者 \r 是一个控制字符,它在DOS/Windows系统中作为换行符的一部分存在,表示将光标移动到行首。在Linux和Unix系统中,换行符只有一个,是一个叫做 Line Feed 的字符,也就是 \n。
因此,当我们在Linux系统中使用cat命令查看一个DOS/Windows系统中的文本文件时,会看到很多 ^M 字符,这是因为 ^M 是 \r 的可见表示。而在Linux系统中,这个字符并不是换行符的一部分,因此需要将它替换掉。
tr命令可以用来替换文本中的字符,其中 -d 选项表示删除指定的字符,因此 tr -d ‘\r’ 表示删除文本中的 \r 字符。所以,使用 tr -d ‘\r’ 命令可以将 DOS/Windows 格式的文本文件转换为 Linux 格式。

col

col [-xb]
选项:
-x:将tab键转换成对的空格键# 示例1 利用cat -A 显示出所有的特殊按键,最后以col 将[TAB]转成空白
[root@localhost ~]# cat -A /etc/man_db.conf 
# 执行完这个命令你就看到很多^I的符号,那就是tab
[root@localhost ~]# cat /etc/man_db.conf | col -x | cat -A |less
# 执行完命令就可以看到所有的[TAB]按键会被替换成为空格键

col的用途就是简单的处理[tab]按键替换成空格键。

join

join翻译成英格利希的意思就是(参加/加入),它是在处理两个文件之前的数据,而且,主要是在处理【两个文件当中,有相同数据的那一行,才将它加在一起的意思。

join [-ti12] file1 file2
选项:
-t:join默认以空格字符分隔数据,并且比对【第一个栏位】的数据如果两个文件相同,则将两条数据连成一行,且第一个栏位放在第一个
-i:忽略大小写的差异
-1:这个是数字的1,代表【第一个文件要用哪个栏位来分析】的意思
-2:代表【第二个文件要用哪个栏位来分析】的意思# 示例1 用root身份,将/etc/passwd与/etc/shadow相关数据整合成一栏
[root@localhost ~]# head -n 3 /etc/passwd /etc/shadow
==> /etc/passwd <==
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin==> /etc/shadow <==
root:$6$0x0W5U0lAIGfNePS$fQegjEeiYdvyV7xK7zyhR9jsXzAwkB6XoA6RxpGo0X/uz8uPhblK9frf36sRtpdyNgJY4jZPQplMR1b/Hqgb9/::0:99999:7:::
bin:*:18353:0:99999:7:::
daemon:*:18353:0:99999:7:::
# 由于输出的数据可以发现在两个文件的最左边栏都是相同账号,且以:分隔
[root@localhost ~]# join -t ':' /etc/passwd /etc/shadow | head -n 3
root:x:0:0:root:/root:/bin/bash:$6$0x0W5U0lAIGfNePS$fQegjEeiYdvyV7xK7zyhR9jsXzAwkB6XoA6RxpGo0X/uz8uPhblK9frf36sRtpdyNgJY4jZPQplMR1b/Hqgb9/::0:99999:7:::
bin:x:1:1:bin:/bin:/sbin/nologin:*:18353:0:99999:7:::
daemon:x:2:2:daemon:/sbin:/sbin/nologin:*:18353:0:99999:7:::
# 通过上面的操作,我们可以将两个文件第一栏位相同者整合成一行
# 第二个文件的相同栏位并不会显示(因为已经在最左边的栏位出现了)# 示例2 我们知道/etc/passwd 第四个栏位是GID
# 这个GID记录在/etc/group 当中的第三个栏位,请问如何将两个文件整合?
[root@localhost ~]# head  -n 3 /etc/passwd /etc/group
==> /etc/passwd <==
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin==> /etc/group <==
root:x:0:
bin:x:1:
daemon:x:2:
# 从上面可以看出确实有相同的部分
[root@localhost ~]# join -t ':' -1 4 /etc/passwd -2 3 /etc/group | head -n 3
0:root:x:0:root:/root:/bin/bash:root:x:
1:bin:x:1:bin:/bin:/sbin/nologin:bin:x:
2:daemon:x:2:daemon:/sbin:/sbin/nologin:daemon:x:# 同样的,相同的栏位部分移动到了最前面,所以第二个文件的内容就每显示

paste

这个paste就要比join简单多了。相对于join必须要比对两个文件的数据相关性,paste就直接将两行贴在一起,且中间以【TAB】键隔开

paste [-d] file1 file2
选项:
-d:后面可以接分隔字符,默认是以【TAB】来分隔
- :如果file部分写错了 -,表示来自标准输入的数据的意思# 示例1 用root的身份,将/etc/passwd与/etc/shadow同行贴在一起,且仅取出前3行
[root@localhost ~]# paste /etc/passwd /etc/shadow |head -n 3
root:x:0:0:root:/root:/bin/bash root:$6$0x0W5U0lAIGfNePS$fQegjEeiYdvyV7xK7zyhR9jsXzAwkB6XoA6RxpGo0X/uz8uPhblK9frf36sRtpdyNgJY4jZPQplMR1b/Hqgb9/::0:99999:7:::
bin:x:1:1:bin:/bin:/sbin/nologin        bin:*:18353:0:99999:7:::
daemon:x:2:2:daemon:/sbin:/sbin/nologin daemon:*:18353:0:99999:7:::
# 注意同一行间是以【TAB】按键隔开的可以仔细看一下# 示例2 先将/etc/group读出(用cat),然后与上述案例的那两个文件忒在一起,且仅取出前3行
[root@localhost ~]# cat /etc/group | paste /etc/passwd /etc/shadow - | head -n 3
root:x:0:0:root:/root:/bin/bash root:$6$0x0W5U0lAIGfNePS$fQegjEeiYdvyV7xK7zyhR9jsXzAwkB6XoA6RxpGo0X/uz8uPhblK9frf36sRtpdyNgJY4jZPQplMR1b/Hqgb9/::0:99999:7:::        root:x:0:
bin:x:1:1:bin:/bin:/sbin/nologin        bin:*:18353:0:99999:7:::        bin:x:1:
daemon:x:2:2:daemon:/sbin:/sbin/nologin daemon:*:18353:0:99999:7:::     daemon:x:2:

expand

这个命令就是在将【TAB】按键转成空格键

expand [-t] file
选项:
-t:后面可接数字,一般来说一个TAB按键可以用8个空格键来替换我们也可以自定义一个【TAB】按键代表多少个字符
# 示例1 将/etc/man_db.conf 内行首的MANPATH的字样就取出,仅取前三行
[root@localhost ~]# grep '^MANPATH' /etc/man_db.conf | head  -n 3
MANPATH_MAP     /bin                    /usr/share/man
MANPATH_MAP     /usr/bin                /usr/share/man
MANPATH_MAP     /sbin                   /usr/share/man
# 行首的 ^ 的意思是找出以MANPATH的行# 示例2 上述案例,如果我想要将所有的符号都列出来来?
[root@localhost ~]# grep '^MANPATH' /etc/man_db.conf | head -n 3 | cat -A
MANPATH_MAP^I/bin^I^I^I/usr/share/man$
MANPATH_MAP^I/usr/bin^I^I/usr/share/man$
MANPATH_MAP^I/sbin^I^I^I/usr/share/man$
# cat -A 可以将【TAB】键显示为【^I】

承接上述案例,我将【TAB】按键设置成6个字符的话?

image-20230427085536345

如果你字符长度设置为 9 或 10就又不同了,还有个命令unexpand是将空格转成【TAB】命令

我们把上述的案例改一下 在让他转成【TAB】命令

[root@localhost ~]# grep '^MANPATH' /etc/man_db.conf | head -n 3 | expand -t 8 -| unexpand -t 8 - | cat -A
MANPATH_MAP^I/bin^I^I^I/usr/share/man$
MANPATH_MAP^I/usr/bin^I^I/usr/share/man$
MANPATH_MAP^I/sbin^I^I^I/usr/share/man$
# 就像这样 好像转空格了 又好像没转,左右摇摆

划分命令:split

split命令它可以帮你将一个大文件,依据文件大小或行数来划分,就可以将大文件划分为小文件了

split [-bl] file PREFIX
选项:
-b:后面可接欲划分成的文件大小,可加单位,例如b、k、m等
-l:以行数来进行划分
PREFIX:代表前缀字符的意思,可作为划分文件的前缀文字# 示例1 我的/etc/services 有600多K,若想要分成300K一个文件时
[root@localhost ~]# cd /tmp/;split -b 300K /etc/services services
[root@localhost tmp]# ll -k services*
-rw-r--r--. 1 root root 307200 Apr 26 16:10 servicesaa
-rw-r--r--. 1 root root 307200 Apr 26 16:10 servicesab
-rw-r--r--. 1 root root  55893 Apr 26 16:10 servicesac
# 这个文件名可随意取,我们只要写上前缀文字,小文件就会以xxxaaa,xxxab,xxxac等方式来建立小文件# 示例2 如何将上面的三个小文件合成一个文件,文件名servicesback
[root@localhost tmp]# cat services* >> servicesback
[root@localhost tmp]# ls -l servicesback /etc/services 
-rw-r--r--. 1 root root 670293 Jun  7  2013 /etc/services
-rw-r--r--. 1 root root 670293 Apr 26 16:13 servicesback# 示例3 使用ls -al /输出的信息中,每十行记录一个文件
[root@localhost tmp]# ls -al /etc/ | split -l 10 - lsroot    
[root@localhost tmp]# wc -l lsroot*0 lsroot10 lsrootaa10 lsrootab10 lsrootac10 lsrootad........
# 重点在这个-号,一般来说如果需要stdout或是stdin时,但偏偏又没有文件
# 有的只是 - 时,那么这个 - 就会被当成 stdin或stdout

参数代码:xargs

xargs是在做什么?以字面的意义来看,x是加减乘除的乘号,args则是参数的意思,所以说这个命令就是在产生某个目录的参数的意思。xargs可以读入stdin的数据,并且以空格符或换行符作为识别符,将stdin的数据分隔为参数。因为是以空格符作为分隔,所以,如果有一些文件名或是其他意义的名词内含有空格符的时候,xargs可能就会误判,用法如下

xargs [-0epn] command
选项:
-0:如果输入stdin含有特殊字符,例如:`、\、空格等特殊字符时,这个-0参数可以将它还原成一般的字符,这个参数可以用于特殊状态
-e:这个是EOF的意思,后面可以接一个字符,当xargs分析到这个1字符时,就会停止工作
-p:在执行每个命令时,都会询问使用者的意思
-n:后面接次数,每次command命令执行时,要使用几个参数的意思
当xargs后面没有接任何命令的时候,默认是以echo 来进行输出# 示例1 将/etc/passwd内的第一栏取出,仅取三行,使用id这个命令将每个账号内容显示出来
[root@localhost ~]# cut -d ':' -f 1 /etc/passwd | head -n 3 | xargs -n 1 id
uid=0(root) gid=0(root) groups=0(root)
uid=1(bin) gid=1(bin) groups=1(bin)
uid=2(daemon) gid=2(daemon) groups=2(daemon)
# 通过-n处理,一次给予一个参数# 示例2 同上,但是执行id时,都要询问使用者是否操作?
[root@localhost ~]# cut -d ':' -f 1 /etc/passwd | head -n 3 | xargs -p  -n 1 id
id root ?...y
uid=0(root) gid=0(root) groups=0(root)
id bin ?...y
uid=1(bin) gid=1(bin) groups=1(bin)
id daemon ?...y
uid=2(daemon) gid=2(daemon) groups=2(daemon)# 示例3 将所有的/etc/passwd内的账号都以id查看,但查到sync就结束命令串
[root@localhost ~]# cat /etc/passwd | head -n 7
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
[root@localhost ~]# cut -d ':' -f 1 /etc/passwd | xargs -e'sync' -n 1 id 
uid=0(root) gid=0(root) groups=0(root)
uid=1(bin) gid=1(bin) groups=1(bin)
uid=2(daemon) gid=2(daemon) groups=2(daemon)
uid=3(adm) gid=4(adm) groups=4(adm)
uid=4(lp) gid=7(lp) groups=7(lp)
# 注意上述案例中那个-e'sync'是连在一起的,中间没有空格
# 可以看到我们查看 /etc/passwd sync在第6行,当分析到第6行内容时就自动停止了

关于减号【-】的用途

管道命令在bash的连续的处理程序中是相当重要的。另外,在日志文件的分析中也是相当的重要。在管道命令中,常常会使用到一个命令的标准输出(stdout)作为这次的标准输入(stdin),某些命令需要用到文件名(例如 tar)来进行处理时,该stdin与stdout可以利用减号【-】来替代,举例来说

[root@localhost ~]# tar -cvf - /home | tar -xvf - -C /tmp/homeback/

上面的例子是说:【我将/home里面的文件给他打包,但打包的数据不是记录到文件,而是传送到stdout,经过管道后,将tar -cvf - /home 串送给后面的 tar -xvf -】后面的这个【-】则是使用前一个命令的stdout,因此,我们就不需要文件名了。

正则表达式是什么

简单来说就是通过一些特殊的符号,可以让用户完成查找 删除 替换

正则表达式分两类:

  • 基本正则表达式(BRE),对应元字符有【 ^ $ . [ ] *】。
  • 扩展正则表达式(ERE) 在BRE基础上增加了 【( ) { } ? + | 】等字符

基本正则表达式集合

符号作用
^尖角号,用于模式的最左侧,如" ^csq " 就是匹配以csq开头的行
$美元符,用于模式的最右侧,如“csq$”,表示以csq结尾的行
^$组合符,表示空行
.匹配任意一个且只有一个字符,不能匹配空行
\转义字符,让特殊含义的符号现出原形,如\ . 代表小数点.
*匹配前一个字符(连续出现) 0次或1次以上,重复0次代表空,即匹配所有内容
.*组合符,匹配所有内容
^.*组合符,匹配任意多个字符开头的内容
.*$组合符,匹配以任意多个字符结尾的内容
[abc]匹配[ ]集合内的任意一个字符,a或b或c,可以写成[a-c]
[^abc]匹配除了^后面的任意字符,a或b或c,^表示对[abc]的取反

扩展正则表达式集合

扩展正则必须用 grep -E 才能生效

字符作用
+匹配前一个字符1次或多次
[ : / ] +匹配括号内的":"或者“/”字符1次或多次
?匹配前一个字符0次或1次
|表示或者,同时过滤多个字符
()分组过滤,被括起来的内容表示一个整体
a{n,m}匹配前一个字符最少n次,最多M次
a{n,}匹配前一个字符最少n次
a{n}匹配前一个字符正好n次
a{,m}匹配前一个字符最多m次

grep(擅长查找功能)

作用:文本搜索工具,根据用户指定的“模式(过滤条件)”对目标文本逐行进行匹配检查,打印匹配到的行

用法: grep [参数选项]... PATTERN [FILE]...
在每个 FILE 或是标准输入中查找 PATTERN。
默认的 PATTERN 是一个基本正则表达式(缩写为 BRE)。
例如: grep -i 'hello world' menu.h main.c
参数选项解释说明
-v排除匹配结果
-n显示匹配行与行号
-i不区分大小写
-c只统计匹配的行数
-E使用扩展正则表达式命令
–color=auto为grep过滤结果添加颜色
-w只匹配过滤的单词
-o只输出匹配的内容

grep配合基本正则表达式案例

测试文件

cat > re.txt  <<EOF
I am a student!
I study Linux.I like play computer game
my blog is https://www.chenshiren.xyz
our site is https://www.chenshiren.xyzmy qq is 222333300
not 222333000.good bey see you.
EOF

(1)^以xxxx开头的行

image-20250917202924699

(2)$以xxxx结尾的行

image-20250917202951991

(3)^$空行

一般排除空行或者包含井号开头的行

排除空行

image-20250917203013439

排除空行和井号开头的行

image-20250917203042946

(4). 任意一个字符

过滤出以.结尾的行

image-20250917203114857

(5)* 前一个字符出现0次或1次以上

出现/重复/连续出现

过滤出所有包含o的行

image-20250917203134363

正则表达式匹配所有或连续出现的时候:贪婪性

过滤以I开头任意内容以game号结尾的行

image-20250917203159903

(6)[][abc]一个整体包含3个情况,匹配a或b或c

过滤a或b或c

image-20250917203250419

过滤大小写字母和数字

image-20250917203329224

过滤出文件中以I或n或g开头的行

image-20250917205424471

过滤出文件中以I或m或n开头的然后结束是数字或字母的

image-20250917205445085

(7)[^][^abc]不匹配a或b或c

不匹配a或b或c

image-20250917205520061

不匹配小写字母

image-20250917205548866

(8)过滤出以.结尾的行

匹配.结尾的行,[]也可以让.变为普通字符

image-20250917205619020

grep配合扩展正则表达式案例

(1)| 或者

找出进程关于sshd和rsyslog的进程,常见的三种写法

image-20250917205722061

(2)+前一个字符出现1次或1次以上

出现/重复/连续出现

经常与[]搭配实现

匹配出re.txt文件中连续出现的单词

image-20250917205744059

只输出re.txt文件中连续出现的单词

image-20250917205814128

取出re.txt文件中连续出现的单词统计次数,取出前5

image-20250917205824892

取出re.txt文件中出现的字母统计次数,取出前5

image-20250917205836145

(3){}o{n,m}前一个字符o,出现至少n次,最多m次

表示范围的匹配,出现1位数字到3位数字

匹配re.txt文件中数字出现的次数最少1次最多3次

image-20250917205904111

匹配ret.txt文件中数字出现的次数等于3次

image-20250917205913112

使用正则匹配ifconfig的地址

image-20250917205927891

(4)()一个整体(sed命令中表示反向引用)

找出lscpu命令中CPU缓冲存储器信息,4种写法

image-20250917210500494image-20250917210353775image-20250917210430322

(5)? 前一个字符出现0次或1次

对比+和*

image-20250917210700638

sed(擅长取行和替换)

sed是Stream Editor(字符流编辑器)的缩写,简称流编辑器。

sed是操作、过滤和转换文本内容的强大工具

其中最常用的功能就是过滤取行(指定行)

用法: sed [选项]... {sed内置命令符} [输入文件]...
选项参数解释
-e进行多项(多次)编辑
-n取消默认输出,只有经过sed特殊处理的那一行才会被列出来
-r使用扩展正则表达式
-i原地编辑(修改文件)
-f指定sed脚本的文件名

常用的处理动作

所有动作都要在单引号里

动作解释
p打印
i在指定行之前插入内容
a在指定行之后插入内容
c替换指定行的所有内容
d删除指定行
s查找并替换
# 测试内容
[root@csq ~]# cat 11.txt 
molly: it's a-ok.
gordon: any problem?
molly: i have trouble talking with my teacher.
gordon: why are you nervous?
molly: i never know how to act around my teacher. i need to review more.
gordon: no problem, i will help you review.
molly: you would do that for me? you are a-ok.

以行为单位新增功能

删除文件1~2行

image-20240314112121681

在第2行和第3行中间加上【hello,NIKO】字样

image-20240314112523398

添加多行?

image-20240314112838112

以行为单位替换与显示功能

将1~2行的内容替换为【No 1~2 number】

image-20240314113053706

仅列出文件的1~2行

image-20240314113350796

部分数据的查找与替换

# 示例1
# 1.先观察原始信息,利用ifconfig查询IP是什么
[root@chenshiren ~]# ifconfig
ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500inet 192.168.200.20  netmask 255.255.255.0  broadcast 192.168.200.255
...
...
# 2.利用grep选取出关键一行的数据
[root@chenshiren ~]# ifconfig ens160 |grep 'inet 'inet 192.168.200.20  netmask 255.255.255.0  broadcast 192.168.200.255
# 3.将IP前后的部分删除
[root@chenshiren ~]# ifconfig ens160 |grep -w 'inet'|sed 's/^.*inet //g' | sed 's/netmask.*$//g' 
#直接使用sed只在屏幕输出替换结果,不修改原文件
192.168.200.20  # 示例2
# 1.使用关键字MAN所在行取出来
[root@chenshiren ~]# cat /etc/man_db.conf |grep -n 'MAN'
12:# MANDATORY_MANPATH                  manpath_element
13:# MANPATH_MAP                path_element    manpath_element
14:# MANDB_MAP          global_manpath  [relative_catpath]
16:# every automatically generated MANPATH includes these fields
18:#MANDATORY_MANPATH                   /usr/src/pvm3/man
20:MANDATORY_MANPATH                    /usr/man
....
# 2.删除掉注释行和空行
[root@chenshiren ~]# cat /etc/man_db.conf |grep  'MAN' |sed 's/#.*$//g' | sed  '/^$/d'
MANDATORY_MANPATH                       /usr/man
MANDATORY_MANPATH                       /usr/share/man
MANDATORY_MANPATH                       /usr/local/share/man
MANPATH_MAP     /bin                    /usr/share/man
MANPATH_MAP     /usr/bin                /usr/share/man
MANPATH_MAP     /sbin                   /usr/share/man
MANPATH_MAP     /usr/sbin               /usr/share/man
MANPATH_MAP     /usr/local/bin          /usr/local/man
MANPATH_MAP     /usr/local/bin          /usr/local/share/man
...
...

直接修改文件内容

# 示例1 将11.test文件中的所有的you换成my 
[root@chenshiren ~]# sed -i 's/you/my/g' 11.txt# 示例2 在文件最后一行加入 【# This  is a test】
[root@chenshiren ~]# sed -i '$a # This is a test\!' 11.txt 
[root@chenshiren ~]# tail -n 1 11.txt 
# This is a test!# 示例3 在每一行添加----分隔
[root@chenshiren ~]# sed -i 'a -------------' 11.txt 
[root@chenshiren ~]# head -n 4 11.txt
molly: it's a-ok.
-------------
gordon: any problem?
-------------
# 示例4 删除-------分隔
[root@chenshiren ~]# sed -i '/^-.*/d' csq.txt

awk(擅长取列)

awk是一个强大的Linux命令,有强大的文本格式化的能力,好比将一些文本数据格式化成专业的excel表样式

awk早期在Unix上实现,我们用的awk是gawk,是GUN awk的意思

image-20230314150105591

awk也是一门编程语言,支持条件判断、数组、循环功能等

awk  options 'pattern[action]'...  filename
# options:awk可选参数
# pattern :条件类型
# action:操作

awk主要是处理每一行的字段内的数据,而默认的字段的分隔符为【空格键】或【Tab】键

# 示例1 使用last将登录者的数据取出来
[root@chenshiren ~]# last |grep -n  'csq'
16:csq      pts/1        192.168.200.1    Tue Mar 12 00:57 - 01:01  (00:03)
17:csq      pts/1        192.168.200.1    Tue Mar 12 00:56 - 00:57  (00:01)
20:csq      pts/2        192.168.200.1    Tue Mar 12 00:06 - 00:07  (00:00)
28:csq      pts/1        192.168.200.1    Sun Mar 10 20:04 - 20:10  (00:06)
29:csq      pts/1        192.168.200.1    Sun Mar 10 20:02 - 20:04  (00:01)
97:csq      pts/1        192.168.200.1    Thu Feb 29 18:40 - crash  (03:46)
101:csq      pts/1        192.168.200.1    Wed Feb 28 18:35 - 19:24  (00:49)
104:csq      pts/2        192.168.200.1    Tue Feb 27 23:29 - crash  (17:57)
# 承上,若我想取出账号与登录者的IP,且账号与IP之间以[TAB]隔开
[root@chenshiren ~]# last  | grep -n 'csq' | awk '{print $1 "\t\t" $3}'         
16:csq          192.168.200.1
17:csq          192.168.200.1
20:csq          192.168.200.1
28:csq          192.168.200.1
29:csq          192.168.200.1
97:csq          192.168.200.1
101:csq         192.168.200.1
104:csq         192.168.200.1
# 每一行的字段都是有变量名称,那就是$1,$2等变量名称
# csq是$1因为是第一栏,IP是第三栏所以就是$3
# $0 代表整个当前行的文本内容,包括该行中所有的字段和分隔符

整个awk的处理流程

  1. 读入第1行,并将第1行的数据写入$0,$1,$2等变量中
  2. 根据”条件类型“的限制,判断是否需要进行后面的操作
  3. 完成所有操作与条件类型
  4. 若还有后续的【行】的数据,则重复上面1~3行步骤,直到所有的数据读完为止

参数

选项说明
-F指定分隔字段符
-v定义或修改一个awk内部变量
-f从脚本文件中读取awk命令

内置变量

变量名称代表意义
ORS输出当前记录分隔符
FS输入字符风隔符,默认为空白字符
OFS输出字段分隔符,默认为空白 字符
RS输入记录分隔符(输入换行符),指定输入时的额换行符
NFnumber of Field,当前行的字段的个数,字段数量
NR行号,当前处理的文本行的行号
FNR各文件分别计数的行号
FILENAME当前文件名
ARGC命令行参数的个数
ARGV数组,保存的是命令行所给定的各参数

img

awk常见用法

# 示例1: 列出每一行的账号($1)以及目前处理的行数(awk内的NR变量),并说明该行有多少字段
[root@chenshiren ~]# last |grep 'csq' |awk '{print $1 "\t lines: " NR "\t columes: "NF}' 
csq      lines: 1        columes: 10
csq      lines: 2        columes: 10
csq      lines: 3        columes: 10
csq      lines: 4        columes: 10
csq      lines: 5        columes: 10
csq      lines: 6        columes: 10
csq      lines: 7        columes: 10
csq      lines: 8        columes: 10# 示例2 awk取本机IP方法
[root@chenshiren ~]# ifconfig  ens160 |awk 'NR==2{print $2}'    
192.168.200.20# 示例3 输出passwd中所有用户名和所对应的shell
[root@chenshiren ~]# awk -F ':' '{print $1 "\t" $7}' /etc/passwd
root    /bin/bash
bin     /sbin/nologin
daemon  /sbin/nologin
adm     /sbin/nologin
lp      /sbin/nologin
sync    /bin/sync
shutdown        /sbin/shutdown
halt    /sbin/halt
mail    /sbin/nologin
....# 示例4 利用OFS输出分隔符分隔开,第一列,第二列,第三列
[root@chenshiren ~]# awk -F ':' -v  OFS='---'  '{print $1,$3,$7}'  /etc/passwd   
root---0---/bin/bash
bin---1---/sbin/nologin
daemon---2---/sbin/nologin
adm---3---/sbin/nologin
lp---4---/sbin/nologin
sync---5---/bin/sync
....
....# 示例5 我们也可以自定义 空格 作为 行分隔符 每遇到一个空格就换行处理
[root@chenshiren ~]# echo {A..Z} > number.txt                     
[root@chenshiren ~]# awk -v RS=' ' '{print NR,$0}' number.txt 
1 A
2 B
3 C
4 D
5 E
6 F
7 G
8 H
9 I
10 J
11 K
12 L
13 M
14 N
15 O
16 P
17 Q
18 R
19 S
20 T
21 U
22 V
23 W
24 X
25 Y
26 Z# 示例6 ORS是输出分隔符的意思,awk默认认为,每一行结束了,就得添加 回车换行符 
[root@chenshiren ~]# awk  -v ORS='\t结束' '{print $0}' number.txt    
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z     结束# 示例7 显示awk正在处理文件的名字
[root@chenshiren ~]# awk -F ":" '{print FILENAME,NR,$1}' /etc/passwd
/etc/passwd 1 root
/etc/passwd 2 bin
/etc/passwd 3 daemon
/etc/passwd 4 adm
/etc/passwd 5 lp
/etc/passwd 6 sync
/etc/passwd 7 shutdown
/etc/passwd 8 halt
/etc/passwd 9 mail
/etc/passwd 10 operator
/etc/passwd 11 games
/etc/passwd 12 ftp
/etc/passwd 13 nobody

变量ARGC,ARGV

ARGV表示的是一个数组,数组中保存的命令行所给的 参数

数组是一种数据类型,如同一个盒子

盒子有它的名字,且内部有N个小格子,标号从0开始

BEGIN表示你在打印动作的时候先做的事

[root@csq ~]# awk 'BEGIN{print "csqcsq"} {print $2}' 22.txt 
csqcsq
csq1
csq6
csq11
csq15

argv[0] 指向程序运行的全路径名

[root@csq ~]# awk 'BEGIN{print "csqcsq"} {print ARGV[0]}' 22.txt 
csqcsq
awk
awk
awk
awk

argv[1] 指向在DOS命令行中执行程序名后的第一个字符串

[root@csq ~]# awk 'BEGIN{print "csqcsq"} {print ARGV[1]}' 22.txt 
csqcsq
22.txt
22.txt
22.txt
22.txt

argv[2] 指向执行程序名后的第二个字符串

[root@csq ~]# awk 'BEGIN{print "csqcsq"} {print  ARGV[0], ARGV[1],ARGV[2]}' 22.txt  33.txt 
csqcsq
awk 22.txt 33.txt
awk 22.txt 33.txt
awk 22.txt 33.txt
awk 22.txt 33.txt
awk 22.txt 33.txt
awk 22.txt 33.txt
awk 22.txt 33.txt
awk 22.txt 33.txt
awk 22.txt 33.txt
awk 22.txt 33.txt
awk 22.txt 33.txt
awk 22.txt 33.txt

awk自定义变量

顾名思义,就是我们自己定义变量

  • 方法①:-v varName=value
  • 方法②:在程序中直接定义

方法①:

[root@chenshiren ~]# awk -F ":" -v filename="/etc/passwd"  'BEGIN{print "文件名:",filename} {print $1"\t"$3"\t"$7}' /etc/passwd
文件名: /etc/passwd
root    0       /bin/bash
bin     1       /sbin/nologin
daemon  2       /sbin/nologin
adm     3       /sbin/nologin
lp      4       /sbin/nologin
sync    5       /bin/sync
shutdown        6       /sbin/shutdown
halt    7       /sbin/halt
mail    8       /sbin/nologin
operator        11      /sbin/nologin
games   12      /sbin/nologin
ftp     14      /sbin/nologin
nobody  65534   /sbin/nologin
...
...

方法②:

[root@csq ~]# [root@chenshiren ~]# awk 'BEGIN{csq1="11111111";csq2="222222222";print csq1,csq2,csq1,csq2}'
11111111 222222222 11111111 222222222# 定义了2个变量,最后打印变量

方法③:间接引用shell变量

[root@csq ~]# Linuxbianliang="这个是Linux定义的变量"
[root@chenshiren ~]# awk -v awkbl=$Linuxbianliang 'BEGIN{print awkbl }'
这个是Linux定义的变量

awk的逻辑运算字符

运算单元代表意义
>大于
<小于
>=大于或等于
<=小于或等于
==等于
!=不等于
# 示例1 在/etc/passwd当中是以":"来作为字段分隔,该文件中第一字段为账号,第三字段是UID
# 那么第三栏小于10以下的数据,并且仅列出账号与第三列
[root@chenshiren ~]# cat /etc/passwd |awk 'BEGIN{FS=":"}  $3 < 10 {print $1,$3}' 
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8# 示例2 假设有一份薪资数据表文件名为pay.txt 内容如下
Name   1st  2nd   3th
csq   2300  2400  2500
zhw   2100  2000  1000
ccc   1000  2000  3000
# 计算总额
[root@chenshiren ~]# awk 'NR>1 {sum=0; for(i=2; i<=NF; i++) sum+=$i; print $1, "Total:", sum}' pay.txt 
csq Total: 7200
zhw Total: 5100
ccc Total: 6000
  • awk的命令间隔:所有awk操作,就是在{}内的操作,如果有需要多个命令辅助时,可利用分号【;】间隔或直接以【Enter】按键来隔开每个命令
  • 逻辑运算当中,如果是【等于】的情况,则务必使用两个等号【==】

printf格式化输出

之前大部分内容都是写的{print}的功能,之呢个对文本简单的输出,并不能美化或者修改格式

printf命令的作用是按照我们指定的格式输出文本

printf命令的语法如下

printf "指定的格式" "文本1" "文本2" "文本3" ......
选项:
关于格式方面的几个特殊样式:\a   警告声音输出\b   退格键\f   清除屏幕\n   输出新的一行\r   就是回车按键\t   水平的[tab]按键\v   垂直的[tab]按键\xNN NN为两位数的数字,可以转换数字成为字符
关于C语言常见的变量格式:%ns  n是数字,代表string,就是多少个字符%ni  n是数字,代表irteger,就是多少个整数位数%N.nf  n与N都是数字,f代表floating(浮点),如果有小鼠位数假设共要十位数,小数点两位即为 %10.2f
printf修饰符:
-:左对齐(默认是右对齐)
+:显示数值符号:printf  "%+d"

在这里插入图片描述

echo 和printf区别

输出文本,echo命令也可以进行输出,它们的无别

[root@csq ~]# echo "mynamecsq"
mynamecsq
[root@csq ~]# printf "mynamecsq"
mynamecsq[root@csq ~]# 
# 在输出文本时,echo会对输出的文本进行换行
# 而printf命令则不会对输出的文本进行换行,我们使用转义符\n就可以换行
[root@csq ~]# printf "mynamecsq\n"
mynamecsq

printf和print的区别

  1. printf:
    • printf 是一个用于格式化输出的函数,可以按照指定的格式输出文本。
    • 它允许使用格式控制符(如 %s%d 等)指定输出的格式和数据类型。
    • 可以通过 printf 来控制输出的对齐和宽度等格式化要求。
    • printf 不会自动换行,需要显式指定换行符 \n 才会换行。
    • 例子:printf "Hello, %s!\n" "World" 会输出 Hello, World! 到标准输出并换行。
  2. print:
    • print 是一个用于输出文本的函数,通常用于打印一行文本到标准输出。
    • print 会自动添加换行符 \n 到输出的文本末尾。
    • print 不支持像 printf 那样的格式化控制符。
    • print 在输出末尾自动换行,不需要显示指定换行符。
    • 例子:print "Hello, World" 会输出 Hello, World 到标准输出并换行。

printf添加格式

格式化字符串%s代表字符串的意思

[root@csq ~]# awk '{printf "%s\n",$1}' 22.txt 
csq
csq5
csq10
csq14

对多个变量进行格式化

当我们使用linux命令printf时,是这样的,一个%s格式替换符,可以对多个参数进行重复格式化

[root@csq ~]# printf "%s\n" a a a a a
a
a
a
a
a

然而awk的格式替换符想要修改多个变量,必须传入多个

[root@chenshiren ~]#  awk 'BEGIN{printf "%d\n%d\n%d\n",1+1,2+2,3+3}'
2
4
6

printf案例

准备测试文件

[root@csq ~]# cat 22.txt 
csq csq1 csq2 csq3 csq4
csq5 csq6 csq7 csq8 csq9
csq10 csq11 csq12 csq13
csq14 csq15 csq16 csq17
[root@csq ~]# awk '{printf "第一列:%s  第二列:%s  第三列:%s\n",$1,$2,$3}' 22.txt 
第一列:csq  第二列:csq1  第三列:csq2
第一列:csq5  第二列:csq6  第三列:csq7
第一列:csq10  第二列:csq11  第三列:csq12
第一列:csq14  第二列:csq15  第三列:csq16
  • awk通过空格切割文档
  • printf动作对数据格式化
# 示例1 对/etc/passwd文件格式化
[root@chenshiren ~]# cat /etc/passwd |awk -v FS=":" 'BEGIN{printf "%-20s\t %-20s\t %-20s\t %-20s\t %-20s\t %-20s\t %-20s\n","用户名","密码","UID","GID","用户注释","用户家目录","用户使用的注释器"} {printf "%-20s\t %-20s\t %-20s\t %-20s\t %-20s\t %-20s\t %-20s\n",$1,$2,$3,$4,$5,$6,$7}'  

image-20240314162522368

# 示例2 假设有一份薪资数据表文件名为pay.txt 内容如下
Name   1st  2nd   3th
csq   2300  2400  2500
zhw   2100  2000  1000
ccc   1000  2000  3000
# 计算总额
[root@chenshiren ~]# cat pay.txt|  awk 'NR==1{printf "%-20s\t %-20s\t %-20s\t %-20s\t %-20s\t\n", $1,$2,$3,$4,"Total"};         
NR>=2{total = $2 + $3 + $4 ; printf "%-20s\t %-20d\t %-20d\t %-20d\t  %-20.2f\t\n",$1,$2,$3,$4,total}'

image-20240314165039305


文章转载自:

http://xALQACWM.Lmqfq.cn
http://YABIeZbq.Lmqfq.cn
http://Fo0jpmyD.Lmqfq.cn
http://qVF786zX.Lmqfq.cn
http://Cyl51P6v.Lmqfq.cn
http://BBTeOm6I.Lmqfq.cn
http://O9KY7hCa.Lmqfq.cn
http://BAdGD1OZ.Lmqfq.cn
http://Dxq7EFYe.Lmqfq.cn
http://CsIQzzaW.Lmqfq.cn
http://y351OcO6.Lmqfq.cn
http://7MWgoOCO.Lmqfq.cn
http://qdF8Ampj.Lmqfq.cn
http://NkhNRp8j.Lmqfq.cn
http://4wdSOj4U.Lmqfq.cn
http://tvF7V0DB.Lmqfq.cn
http://x665vRMn.Lmqfq.cn
http://KVKfzaWD.Lmqfq.cn
http://cfpnQlWb.Lmqfq.cn
http://fdIxkyrX.Lmqfq.cn
http://A5CIzWYj.Lmqfq.cn
http://FxM8dYLo.Lmqfq.cn
http://QNIOfPKI.Lmqfq.cn
http://8CNqQNlm.Lmqfq.cn
http://v0H5Eppz.Lmqfq.cn
http://DqZX0RyD.Lmqfq.cn
http://Z2GBMTST.Lmqfq.cn
http://n1dnlwFe.Lmqfq.cn
http://OyerNtQu.Lmqfq.cn
http://dDcDJMdm.Lmqfq.cn
http://www.dtcms.com/a/387303.html

相关文章:

  • 破垄断!东土科技与海光信息联合发布全国产化工控系统,筑牢工业安全新底座
  • 一场史诗级的冒险——Docker命令大航海!
  • 基于 Node.js 的后端框架:NestJS 和 Express(二)
  • 大数据时代时序数据库选型指南:为何Apache IoTDB成优选——从技术架构与行业实践深度剖析
  • HBase 实战:3 步掌握基于 Rowkey 的数据更新技巧
  • 【Android】Jetpack Media3 播放音频文件
  • 算法 --- 队列 + 宽搜(BFS)
  • 苹果手机怎么导出App数据目录,iOS文件管理、应用沙盒访问、日志缓存导出与性能调试实战(uni-app开发者指南)
  • Java 设计模式——策略模式:从 3 种写法到 SpringBoot 进阶
  • JVM:性能调优的理解
  • AR眼镜在巡检业务中的软件架构设计|阿法龙XR云平台
  • 活动预告 | Paraverse × Unity:Unity云XR串流——突破设备与平台限制
  • 第十四届蓝桥杯青少组C++选拔赛[2022.12.18]第二部分编程题(5、猴子拿桃)
  • 二维码辅助回桩之二维码识别
  • Mojo vs Python vs Rust,2025年搞AI,怎么学
  • 从软件工程角度谈企业管理
  • 【C语言】C 语言自定义类型:联合与枚举的基础解析
  • 模型部署:(五)安卓端部署Yolov8关键点检测项目全流程记录
  • 在业务应用中集成 go-commons,实现应用+系统双指标监控
  • ESP32-C3四种工作模式
  • ReactNative中实现可拖拽的温度计组件
  • react snippets
  • 基于Matlab高低频混合建模的大气湍流相位屏生成算法
  • 2025年8月SCI-袋鼠逃生优化算法Kangaroo Escape Optimizer-附Matlab免费代码
  • Node.js 创建 TCP 服务
  • 关于鸿蒙配置HMRouter的问题,比如白屏等
  • 为什么 socket.io 客户端在浏览器能连接服务器但在 Node.js 中报错 transport close?
  • Express框架介绍(基于Node.js的轻量级、灵活的Web应用框架)
  • Lustre Ceph GlusterFS NAS 需要挂载在k8s容器上,数据量少,选择哪一个存储较好
  • Axios与Java Spring构建RESTful API服务集成指南