- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
众所周知,bash命令执行的时候会输出信息,但有时这些信息必须要经过几次处理之后才能得到我们想要的格式,此时应该如何处置?这就牵涉到 管道命令(pipe) 了。管道命令使用的是 | 这个界定符号。另外,管道命令与连续执行命令是不一样的,这点下面我们会说明.
我们先来看一个管道命令的例子。假设我们需要看 /etc 目录下有多少文件,那么可以利用 ls /etc 来查看,不过由于文件数量太多,导致一口气就将屏幕塞满了,而不知道前面输出的内容是啥:
root@orion-orion:~ ls -al /etc root@qi
total 944
drwxr-xr-x 1 root root 4096 Feb 19 11:38 .
drwxr-xr-x 1 root root 4096 Nov 23 2021 ..
drwxr-xr-x 3 root root 4096 Jun 5 2021 .java
...
drwxr-xr-x 2 root root 4096 Jul 24 2018 xfce4
此时,我们可以使用 less 命令的协助:
root@orion-orion:~ ls -al /etc | less
total 944
drwxr-xr-x 1 root root 4096 Feb 19 11:38 .
drwxr-xr-x 1 root root 4096 Nov 23 2021 ..
drwxr-xr-x 3 root root 4096 Jun 5 2021 .java
:
如此一来,使用 ls 命令输出的内容就能够被 less 读取,并且利用 less 的功能,我们就能够前后翻动相关的信息了。其中的关键就是这个管道命令 | 。管道命令 | 仅能处理前一个命令传来的 标准输出 信息,而对于标准错误信息并没有直接处理能力。那么整体的管道命令可以使用下图表示:
在每个管道后面接的第一个数据必定是 命令 ,而且 这个命令必须要能够接受标准输出的数据 才行,这样的命令才可为管道命令。例如 less 、 grep 、 sed 、 awk 等都是可以接受标准输入的管道命令,而 ls 、 cp 、 mv 就不是管道命令,因为它们并不会接受来自stdin的数据。总结一下,管道命令主要有两个需要注意的地方:
如果我们强行让标准错误为管道命令所用,那么可以使用 2>&1 将标准错误 2> 重定向到标准输出 1> .
接下来我们选取 grep 、 sed 、 awk 这三个用于文本处理的管道命令来进行介绍。这三个命令可谓是Linux下操作文本的三大利器,合称 Linux文本处理三剑客 .
grep
grep 命令可以 一行一行 地分析信息,若 某行含有我们所需要的信息,则就将该行拿出来 。简单的语法如下:
grep [-acinv] [--color=auto] '查找字符' filename
它的选项与参数如下:
-a
:将二进制文件以文本文件的方式查找数据。 -c
:计算找到 '查找字符'
的次数。 -i
:忽略大小写的不同,所以大小写视为相同。 -n
:顺便输出行号。 -v
:反向选择,亦即显示出没有 '查找字符'
内容的那些行。 下面展示几个例子.
范例一 :将 last 当中,有出现 root 的那一行就显示出来.
root@orion-orion:~ last | grep 'root'
root pts/2 10.249.252.8 Mon Apr 6 06:08 - 09:02 (02:54)
root pts/1 10.249.252.8 Mon Apr 6 06:05 - 06:08 (00:03)
root pts/1 10.249.252.8 Mon Apr 6 03:13 - 06:05 (02:51)
...
root pts/1 :1 Tue Jul 24 06:44 - 06:45 (00:00)
root pts/1 172.17.0.1 Tue Apr 10 14:23 - 14:23 (00:00)
root pts/1 127.0.0.1 Tue Apr 10 08:57 - 08:57 (00:00)
这里前3行是我们校内的局域网IP(以 10.249 打头), 172.17.0.1 是Docker中默认网桥 docker0 的IP地址, 127.0.0.1 为本地回环地址。 范例二 :与范例一相反,只要没有 root 的就取出.
root@orion-orion:~ last | grep -v 'root'
person pts/1 127.0.0.1 Tue Apr 10 08:54 - 08:54 (00:00)
范例三 :在 last 的输出信息中,只要有 root 就取出,并且仅取第一栏:
root@orion-orion:~ last | grep "root" | awk '{print $1}'
root
root
root
...
这里用到了我们后面要讲的 awk 命令,这一命令用于将一行分为多个字段来处理,我们后面将会详细介绍。 范例四 :取出 /etc/adduser.conf 内含 UID 的那几行,且将找到的关键字部分用特殊颜色显示出来:
root@orion-orion:~ grep --color=auto "UID" /etc/adduser.conf root@qi
# FIRST_SYSTEM_[GU]ID to LAST_SYSTEM_[GU]ID inclusive is the range for UIDs
# package, may assume that UIDs less than 100 are unallocated.
FIRST_SYSTEM_UID=100
LAST_SYSTEM_UID=999
# FIRST_[GU]ID to LAST_[GU]ID inclusive is the range of UIDs of dynamically
FIRST_UID=1000
LAST_UID=29999
可以看到找到的关键字部分用红色显示(当然这里的代码块看不出来效果,需要在终端进行渲染)。注意,在我的Ubuntu 18.04系统中 默认的 grep 已经主动使用 --color=auto 选项在 alias 中了 ,因此不用手动加 --color=auto 也会标红(事实上,在我本地的Mac系统中也是如此).
sed
前面我们说过, grep 命令可以解析一行文字,若该行含有某关键词就会将其整行列出来。接下来我们要讲的 sed 命令也是一个管道命令(可以分析标准输入),它还可以 对特定行进行新增、删除、替换等 。 sed 的用法如下:
sed [-nefr] [操作]
它的选项与参数如下:
-n
:使用安静(silent)模式。在一般的 sed
用法中,所有来自 stdin
的数据一般都会被列出到屏幕上,但如果加上 -n
参数后,则只有经过 sed
选择的那些行才会被列出来。 -e
:使 sed
的操作结果由屏幕输出,而改变原有文件(默认已选该参数, 与 -i
的直接修改文件相反)。 -f
:从一个文件内读取将要执行的 sed
操作, -f filename
可以执行 filename
中写好的 sed
操作。 -r
: sed
的操作使用的是扩展型正则表达式的语法(默认是基础正则表达式语法)。 -i
:直接修改读取的文件内容,而不是由屏幕输出。 关于其中的 [操作] 部分,其格式如下:
[n1[,n2]]function
n1, n2 :不一定会存在,一般代表 选择进行操作的行数 ,比如我的操作需要在10到20行之间进行,则写为 10, 20[操作名称] .
具体地,对行的操作函数 function 包括下面这些东西:
a
:新增, a
的后面可以接字符,这些字符将被添加在 n1
/ n2
的 下一行 ; c
:替换, c
的后面可以接字符,这些字符可以替换 n1
, n2
之间的行; d
:删除,因为是删除,所以 d
后面通常不需要接任何东西; i
:插入, i
的后面可以接字符,这些字符将被添加在 n1
/ n2
的 上一行 ; p
:打印,亦即将某些选择的行打印出来。通常 p
会与参数 sed -n
一起运行。 s
:替换,可以直接进行替换的工作,通常这个 s
的操作可以搭配正则表达式。 下面我们来举几个例子进行说明.
以行为单位的新增/删除功能 。
范例一 :查看 /etc/passwd 文件的内容并且在每一行前面加上行号,同时将 2-5 行删除.
root@orion-orion:~ cat -n /etc/passwd | sed '2,5d'
1 root:x:0:0:root:/root:/bin/zsh
6 games:x:5:60:games:/usr/games:/usr/sbin/nologin
7 man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
8 lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
...
可以看到 sed 的操作为 2,5d ,也即删除2~5行,所以显示的数据就没有2~5行。此外,请注意原本应该是要执行 sed -e 才对,不过这里没有 -e 也行,因为已经默认选了。同时也要注意 sed 后面接的操作务必以两个单引号 '' 括住.
我们将范例变一下,如果要删除第2行,那么可以使用 cat -n /etc/passwd | sed '2d' ;如果是要删除第3到最后一行,则是 cat -n /etc/passwd | sed '3,$d' ,这里美元符号 $ 代表最后一行.
范例二 : 承接上题,在第2行后(亦即是第3行)加上 drink tea 字样.
root@orion-orion:~ cat -n /etc/passwd | sed '2a Drink tea?'
1 root:x:0:0:root:/root:/bin/zsh
2 daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
Drink tea?
3 bin:x:2:2:bin:/bin:/usr/sbin/nologin
...
如果想要加在第2行前面,将新增操作改为插入操作,即 cat -n /etc/passwd | sed '2i Drink tea?' 就行了.
范例三 :继续承接上题,现在我们想要在第2行后面加上两行字,例如 Drink tea or... 与 Drink beer?
root@orion-orion:~ cat -n /etc/passwd | sed '2a Drink tea or...\ root@qi
\ Drink beer?'
1 root:x:0:0:root:/root:/bin/zsh
2 daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
Drink tea or...
Drink beer?
3 bin:x:2:2:bin:/bin:/usr/sbin/nologin
这里的重点在于我们可以不只增加一行,可以增加很多行,但每一行之间必须以反斜杠 \ 来进行新行的增加.
以行为单位的替换与显示功能 。
刚刚是介绍如何新增与删除行。接下来我们看看如何进行整行的替换.
范例四 :我想将2~5行的内容替换为 No 2-5 number .
root@orion-orion:~ cat -n /etc/passwd | sed '2,5c No 2-5 number`
1 root:x:0:0:root:/root:/bin/zsh
No 2-5 number
6 games:x:5:60:games:/usr/games:/usr/sbin/nologin
...
除此之外, sed 还有很有趣的功能,以前我们想要列出第11~25行,得用 head -n 20 或 tail -n 10 之类的命令来处理,很麻烦。而 sed 则可以直接取出你想要的那几行,这是通过行号来识别的。例如下面这个范例:
范例五 :仅列出 /etc/passwd 文件内的第5-7行.
root@orion-orion:~ cat -n /etc/passwd | sed -n '5,7p'
5 sync:x:4:65534:sync:/bin:/bin/sync
6 games:x:5:60:games:/usr/games:/usr/sbin/nologin
7 man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
注意,这里必须要加 -n 表示安静模式。如果不加 -n 改为 sed 5,7p ,那么第5-7行会重复输出:
root@orion-orion:~ cat -n /etc/passwd | sed '5,7p'
1 root:x:0:0:root:/root:/bin/zsh
2 daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
3 bin:x:2:2:bin:/bin:/usr/sbin/nologin
4 sys:x:3:3:sys:/dev:/usr/sbin/nologin
5 sync:x:4:65534:sync:/bin:/bin/sync
5 sync:x:4:65534:sync:/bin:/bin/sync
6 games:x:5:60:games:/usr/games:/usr/sbin/nologin
6 games:x:5:60:games:/usr/games:/usr/sbin/nologin
7 man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
7 man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
8 lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
...
部分数据的查找并替换的功能 。
除了整行的处理模式之外, sed 还可以对某行进行部分数据的查找和替换。基本上 sed 的查找与替换与 vi 相当的类似,它的格式如下所示:
sed 's/要被替换的字符/新的字符/g'
接下来我们来看一个取得IP数据的范例,我们将该任务拆解为多步,一段一段地处理.
步骤一:先观察原始信息,利用 /sbin/ifconfig 查询IP是什么?
root@orion-orion:~ /sbin/ifconfig eth0
eth0 Link encap:Ethernet HWaddr 02:42:ac:11:00:0c
inet addr:172.17.0.12 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:49498631 errors:0 dropped:0 overruns:0 frame:0
TX packets:41131666 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:51467728818 (51.4 GB) TX bytes:40995045195 (40.9 GB)
我们希望用关键词识别出 172.17.0.12 ,这是我所用学校服务器的内网私有IP地址.
步骤二:利用关键字配合 grep 选取出 inet 所在的那关键的一行.
root@orion-orion:~ /sbin/ifconfig eth0 | grep 'inet '
inet addr:172.17.0.12 Bcast:172.17.255.255 Mask:255.255.0.0
好了,现在只剩下一行了,但我们想只留下IP地址 addr:172.17.0.12 而将其它部分统统删除.
步骤三:先将IP前面的部分予以删除(用到正则表达式).
root@orion-orion:~ /sbin/ifconfig eth0 | grep 'inet ' | sed 's/^.*inet //g'
addr:172.17.0.12 Bcast:172.17.255.255 Mask:255.255.0.0
这里正则表达式中的 ^ 表示待查找的字符串在行首; . 表示一定有一个任意字符, * 表示重复前一个字符0到无穷多次,连在一起的 .* 就表示任意字符重复任意次; // 之间为空,也就表示删除的意思.
步骤四:将IP后面的部分也予以删除.
root@orion-orion:~ /sbin/ifconfig eth0 | grep 'inet ' | sed 's/^.*inet //g' \
\ | sed 's/ *Bcast.*$//g'
addr:172.17.0.12
这里 ' *' 表示空格重复任意次; .* 表示任意字符重复任意次; $ 表示待查找的字符串在行尾.
我们再来继续研究 sed 与正则表达式的配合练习。假设我们只要 /etc/adduser.conf 文件中 UID 存在的那几行数据,但是有 # 在内的注释我们不要,而且空白行我们也不要,那么应该如何处理?可以通过这几个步骤来实践看看:
步骤一:先用 grep 将关键字 UID 所在行取出来.
root@orion-orion:~ cat /etc/adduser.conf | grep 'UID'
# FIRST_SYSTEM_[GU]ID to LAST_SYSTEM_[GU]ID inclusive is the range for UIDs
# package, may assume that UIDs less than 100 are unallocated.
FIRST_SYSTEM_UID=100
LAST_SYSTEM_UID=999
# FIRST_[GU]ID to LAST_[GU]ID inclusive is the range of UIDs of dynamically
FIRST_UID=1000
LAST_UID=29999
步骤二:删除掉注释之后的内容:
root@orion-orion:~ cat /etc/adduser.conf | grep 'UID' | sed 's/#.*$//g'
FIRST_SYSTEM_UID=100
LAST_SYSTEM_UID=999
FIRST_UID=1000
LAST_UID=29999
这样原本注释的内容都变成了空白行,接下来我们删除空白行:
root@orion-orion:~ cat /etc/adduser.conf | grep 'UID' | sed 's/#.*$//g' | sed '/^$/d'
FIRST_SYSTEM_UID=100
LAST_SYSTEM_UID=999
FIRST_UID=1000
LAST_UID=29999
注意这里的 ^$ 表示行首 ^ 和行尾 $ 之间没有字符,也即空白行.
直接修改文件内容(危险操作) 。
sed 的能耐可不止于我们上面所说的,它甚至可以直接修改文件的内容,而不必使用管道命令或数据流重定向。不过这个操作会修改到原始的文件,所以请你千万不要随便拿系统配置文件来测试。我们下面使用 regular_express.txt 文件来测试(文件可以去鸟哥的官网下载: regular_express.txt ).
root@orion-orion:~ cat regular_express.txt root@qi
"Open Source" is a good mechanism to develop programs.
apple is my favorite food.
Football game is not use feet only.
this dress doesn't fit me.
...
go! go! Let's go.
# I am VBird
范例六:利用 sed 将 regular_express.txt 内每一行结尾若为 . 则换成 ! .
root@orion-orion:~ sed -i 's/\.$/\!/g' regular_express.txt
root@orion-orion:~ cat regular_express.txt
"Open Source" is a good mechanism to develop programs!
apple is my favorite food!
Football game is not use feet only!
this dress doesn't fit me!
...
go! go! Let's go!
# I am VBird
上面的 -i 选项可以让你的 sed 直接去修改后面所接的文件内容而不是由屏幕输出.
范例七:利用 sed 直接在 regular_express.txt 最后一行加入 # This is a test .
root@orion-orion:~ sed -i '$a # This is a test' regular_express.txt
root@orion-orion:~ tail regular_express.txt
...
go! go! Let's go!
# I am VBird
# This is a test
由于 $ 代表的是最后一行,而 a 的操作是新增,因此是该文件最后新增.
sed 的 -i 选项可以直接修改文件内容,因此这功能非常有帮助。比如如果你有一个100万行的文件,你要在第100行加某些文字,此时使用vim可能会疯掉,因为文件太大了。此时就可以利用 sed 来直接修改与替换,而不需要使用 vim 去修改了.
awk
相较于 sed 常常对一整行进行操作, awk 则倾向于 将一行分为多个字段来处理 。因此, awk 相当适合处理小型的文本数据,其运行模式通常是这样的:
awk '{条件类型1{操作1} 条件类型2{操作2} ...}' filename
awk 后接两个 单引号 并加上大括号 {} 来设置想要对数据进行的处理操作。 awk 可以处理后续接的文件,也可以读取来自前一个命令的标准输出。如前面所说, awk 主要是将每一行分为多个字段来处理,而默认的字段分隔符为 空格键 或 [Tab]键 。举例来说,我们用 last 将登陆者的数据取出来(仅取出前3行):
root@orion-orion:~ last -n 3
root pts/292 10.249.45.37 Wed Mar 29 06:55 - 09:14 (02:19)
root pts/292 10.249.45.37 Tue Mar 28 13:17 - 16:14 (02:56)
root pts/292 10.249.45.37 Tue Mar 28 12:35 - 13:17 (00:42)
wtmp begins Tue Apr 10 08:54:45 2018
若我想取出账号与登陆者的IP,且账号与IP之间以 [Tab] 隔开,则会变成这样:
root@orion-orion:~ last -n 3 | awk '{print $1 "\t" $3}' root@qi
root 10.249.45.37
root 10.249.45.37
root 10.249.45.37
注意, awk 的所有后续操作都是以单引号括住的,而 awk 的格式内容如果想要以 print 打印时,记得 将非变量的文字部分使用双引号括起来 ,因为单引号已经是 awk 命令的固定用法了。此外,因为这里无论哪一行我们都要处理,因此就不需要有 条件类型 的限制.
另外,由上面的例子我们看到,在 awk 的括号内,每一行的每个字段都有变量名称( $1 , $2 等)。在上面的例子中, root 位于第1栏,故其变量名称为 $1 ;而 10.249.45.37 是第3栏,故它是 $3 ,后面以此类推。还有个变量比较特殊,那就是 $0 ,它表示 一整行数据 。由此可知,刚刚上面5行当中,整个 awk 的处理流程就是:
$0
,然后将其拆分为多个字段并写入 $1
、 $2
、 $3
等变量当中。 条件类型
的限制,判断是否需要进行后面的 操作
(在上面这个例子中没有 条件类型
)。 经过这样的步骤,我们看到了 awk 是 以行为一次处理的单位 ,而 以字段为最小的处理单位 。好了,那么如何快速地获得我们的数据有几行几列呢?这就需要 awk 的内置变量的帮忙.
变量名称 | 代表意义 |
---|---|
NF |
每一行(也即 $0 )所拥有的字段总数 |
NR |
目前 awk 所处理的是第几行数据 |
FS |
目前的分割字符,默认是空格键 |
我们继续以上面 last -n 3 的例子来做说明,如果我想要:
$1
); awk
内的 NR
变量); awk
内的 NF
字段); 则可以这样:
root@orion-orion:~ last -n 5 | awk '{print $1 "\t lines: " NR "\t columns: " NF}'
root lines: 1 columns: 10
root lines: 2 columns: 10
root lines: 3 columns: 10
lines: 4 columns: 0
wtmp lines: 5 columns: 7
注意,在 awk 内的 NR 、 NF 等变量要用大写,且不需要有美元符号 $ .
接下来我们来看一看所谓的“条件类型”.
awk 的逻辑运算字符 既然要用到“条件”的类别,那么自然就需要一些逻辑运算,如下所示:
运算单元 | 代表意义 |
---|---|
> |
大于 |
< |
小于 |
>= |
大于或等于 |
<= |
小于或等于 |
== |
等于 |
!= |
不等于 |
注意,逻辑运算即所谓的大于、小于等于等判断式上面,习惯上用 == 而不是 = 来表示, = 符号在 awk 操作这里留给了变量赋值用.
我们来看下面一个例子。比如在 /etc/passwd 中是以冒号 : 来作为字段的分隔,该文件中第一字段为账号,第三字段为 UID 。如下所示:
root@orion-orion:~ cat /etc/passwd | less root@qi
root:x:0:0:root:/root:/bin/zsh
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
...
dnsmasq:x:115:65534:dnsmasq,,,:/var/lib/misc:/bin/false
那假设我要查看第三栏小于10的数据,并且仅列出账号与第三列,那么可以这样做:
root@orion-orion:~ cat /etc/passwd | awk '{FS=":"} $3 < 10 {print $1 "\t " $3}'
root:x:0:0:root:/root:/bin/zsh
daemon 1
bin 2
...
诶,不过怎么第一行没有正确地显示出来?这是因为我们在读入第一行的时候,那些变量 $1 、 $2 等等默认还是以 空格键 做为分割,所以虽然我们定义了 FS=":" ,但却仅能在第二行后才开始生效。那怎么办呢?我们可以预先设置 awk 的变量,利用 BEGIN 这个关键词,这样做:
root@orion-orion:~ cat /etc/passwd | awk 'BEGIN {FS=":"} $3 < 10 {print $1 "\t " $3}'
root 0
daemon 1
bin 2
...
接下来我们来看如何用 awk 来完成计算功能.
假设我们有一个薪资数据表文件为 pay.txt ,内容如下:
root@orion-orion:~ cat pay.txt
Name 1st 2nd 3th
VBird 23000 24000 25000
DMTsai 21000 20000 23000
Bird2 43000 42000 41000
如何来计算每个人 1st 、 2nd 、 3th 的总额呢?而且我们还需要格式化输出。我们可以这样考虑:
NR==1
时处理)。 NR>=2
以后处理)。
root@orion-orion:~ cat pay.txt | \
awk 'NR == 1 {printf "%10s %10s %10s %10s %10s\n", $1, $2, $3, $4, "Total"} \
NR >= 2 {total = $2 + $3 + $4; \
printf "%10s %10d %10d %10d %10.2f\n", $1, $2, $3, $4, total}'
Name 1st 2nd 3th Total
VBird 23000 24000 25000 72000.00
DMTsai 21000 20000 23000 64000.00
Bird2 43000 42000 41000 126000.00
上面的例子有几个重要事项应该要先说明:
awk
的命令间隔:所有 awk
的操作,亦即在 {}
里的操作,如果有需要多个命令辅助时,可利用分号 ;
间隔。 ==
; \n
,才能分行(这里注意可以和Python的 print
函数和shell的 echo
函数做对比,此二者自带换行); awk
中的变量可以直接使用,不需要加上 $
符号。 另外, awk 的操作内 {} 也是支持 if( 条件 ) 的,比如上面的命令也可以写为:
root@orion-orion:~ cat pay.txt | \
awk '{if (NR == 1) printf "%10s %10s %10s %10s %10s\n", $1, $2, $3, $4, "Total"} \
NR >= 2 {total = $2 + $3 + $4; \
printf "%10s %10d %10d %10d %10.2f\n", $1, $2, $3, $4, total}'
Name 1st 2nd 3th Total
VBird 23000 24000 25000 72000.00
DMTsai 21000 20000 23000 64000.00
Bird2 43000 42000 41000 126000.00
第一种写法相较于第二种写法更好,因为比较有统一性.
除此之外, awk 还可以帮我们进行循环计算,不过那属于比较高级的单独课程了,这里就不再多加以介绍.
情景模拟题一 。
通过 grep 配合子命令 $(command) 来从大量文件中查找含有星号 * 的文件与内容.
/etc
下面找出含有星号 *
的文件与内容。
root@orion-orion:~ grep '\*' /etc/* 2> /dev/null
/etc/adduser.conf:#NAME_REGEX="^[a-z][-a-z0-9_]*\$"
/etc/bash.bashrc:#xterm*|rxvt*)
/etc/bash.bashrc:#*)
...
注意,这里单引号 '' 内的型号是正则表达式的字符,但由于我们要找的是星号,因此需要加上转义符 \ ;而 /etc/* 的那个 * 是bash通配符中的“万用字符”,在这里代表拥有任意多个字符的文件名.
不过在上述的这个例子中,我们仅能找到 /etc 下第一层子目录的数据,无法找到次目录的数据。如果想要连同完整的 /etc 此目录数据,就得要这样做:
root@orion-orion:~ grep '\*' $(find /etc -type f) 2> /dev/null
Binary file /etc/ld.so.cache matches
/etc/xdg/xfce4/xinitrc: for i in ${XDG_CONFIG_HOME}/autostart/*.desktop; do
/etc/xdg/xfce4/xinitrc: x|xno*)
/etc/xdg/xfce4/xinitrc: *)
...
如果只想列出文件名而不想列出内容的话,可以加个 -l 参数:
root@orion-orion:~ grep -l '\*' $(find /etc -type f) 2> /dev/null
/etc/ld.so.cache
/etc/xdg/xfce4/xinitrc
/etc/xdg/Thunar/uca.xml
/etc/skel/.bashrc
...
/
的话:
root@orion-orion:~ grep '\*' $(find / -type f) 2> /dev/null
芜湖,一运行这个命令,由于要打印的东西太多,终端直接卡死。这下该如何是好呢?此时我们可以通过管道命令以及 xargs 来处理。比如,让 grep 每次仅能处理 10 个文件名,我们可以:
a. 先用 find 去找出文件; b. 用 xargs 将这些文件每次丢10个给 grep 来作为参数处理; c. grep 实际开始查找文件内容; 。
所以整个做法会变成这样:
root@orion-orion:~ find / -type f 2> /dev/null | xargs -n 10 grep '\*'
Binary file /sbin/chcpu matches
Binary file /sbin/sulogin matches
Binary file /sbin/pivot_root matches
...
然而,从输出的结果看,数据量实在非常庞大,如果我们只想知道文件名的话也可以给 grep 加上 -l 参数:
root@orion-orion:~ find / -type f 2> /dev/null | xargs -n 10 grep -l '\*'
/sbin/chcpu
/sbin/sulogin
/sbin/pivot_root
...
情景模拟题二 。
使用管道命令配合正则表达式建立新命令与新变量。我们想要建立一个名为 myip 的新命令,这个命令能够将我系统的IP识别出来并显示。而且我们想要有个新变量 MYIP 来记录我们的IP.
处理的方式如下所示:
ifconfig
、 sed
与 awk
来取得我们的IP:
root@orion-orion:~ ifconfig eth0 | grep 'inet ' | sed 's/^.*inet //g' | sed 's/ *Bcast.*$//g'
addr:172.17.0.12
alias
指定为 myip
,如下所示:
root@orion-orion:~ alias myip="ifconfig eth0 | grep 'inet ' | sed 's/^.*inet //g' | \
\ sed 's/ *Bcast.*$//g'"
root@orion-orion:~ myip
addr:172.17.0.12
MYIP
。
root@orion-orion:~ MYIP=$(myip)
~/orion-orion echo $MYIP
addr:172.17.0.12
alias
与 MYIP
设置的那两行写入你的 ~/.bashrc
即可。 最后此篇关于Linux:管道命令与文本处理三剑客(grep、sed、awk)的文章就讲到这里了,如果你想了解更多关于Linux:管道命令与文本处理三剑客(grep、sed、awk)的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在使用 Assets 管道来管理我的 Grails 3.0 应用程序的前端资源。但是,似乎没有创建 CoffeeScript 文件的源映射。有什么办法可以启用它吗? 我的 build.gradle
我有一个我想要的管道: 提供一些资源, 运行一些测试, 拆资源。 我希望第 3 步中的拆卸任务运行 不管 测试是否通过或失败,在第 2 步。据我所知 runAfter如果前一个任务成功,则只运行一个任
如果我运行以下命令: Measure-Command -Expression {gci -Path C:\ -Recurse -ea SilentlyContinue | where Extensio
我知道管道是一个特殊字符,我需要使用: Scanner input = new Scanner(System.in); String line = input.next
我再次遇到同样的问题,我有我的默认处理方式,但它一直困扰着我。 有没有更好的办法? 所以基本上我有一个运行的管道,在管道内做一些事情,并想从管道内返回一个键/值对。 我希望整个管道返回一个类型为 ps
我有三个环境:dev、hml 和 qa。 在我的管道中,根据分支,阶段有一个条件来检查它是否会运行: - stage: Project_Deploy_DEV condition: eq(varia
我有 Jenkins Jenkins ver. 2.82 正在运行并想在创建新作业时使用 Pipeline 功能。但我没有看到这个列为选项。我只能在自由式项目、maven 项目、外部项目和多配置之间进
在对上一个问题 (haskell-data-hashset-from-unordered-container-performance-for-large-sets) 进行一些观察时,我偶然发现了一个奇
我正在寻找有关如何使用管道将标准输出作为其他命令的参数传递的见解。 例如,考虑这种情况: ls | grep Hello grep 的结构遵循以下模式:grep SearchTerm PathOfFi
有没有办法不因声明性管道步骤而失败,而是显示警告?目前我正在通过添加 || exit 0 来规避它到 sh 命令行的末尾,所以它总是可以正常退出。 当前示例: sh 'vendor/bin/phpcs
我们正在从旧的 Jenkins 设置迁移到所有计划都是声明性 jenkinsfile 管道的新服务器……但是,通过使用管道,我们无法再手动清除工作区。我如何设置 Jenkins 以允许 手动点播清理工
我在 Python 中阅读了有关 Pipelines 和 GridSearchCV 的以下示例: http://www.davidsbatista.net/blog/2017/04/01/docume
我有一个这样的管道脚本: node('linux'){ stage('Setup'){ echo "Build Stage" } stage('Build'){ echo
我正在使用 bitbucket 管道进行培训 这是我的 bitbucket-pipelines.yml: image: php:7.2.9 pipelines: default:
我正在编写一个程序,其中输入文件被拆分为多个文件(Shamir 的 secret 共享方案)。 这是我想象的管道: 来源:使用 Conduit.Binary.sourceFile 从输入中读取 导管:
我创建了一个管道,它有一个应该只在开发分支上执行的阶段。该阶段还需要用户输入。即使我在不同的分支上,为什么它会卡在这些步骤的用户输入上?当我提供输入时,它们会被正确跳过。 stage('Deplo
我正在尝试学习管道功能(%>%)。 当试图从这行代码转换到另一行时,它不起作用。 ---- R代码--原版----- set.seed(1014) replicate(6,sample(1:8))
在 Jenkins Pipeline 中,如何将工件从以前的构建复制到当前构建? 即使之前的构建失败,我也想这样做。 最佳答案 Stuart Rowe 还在 Pipeline Authoring Si
我正在尝试使用 执行已定义的作业构建 使用 Jenkins 管道的方法。 这是一个简单的例子: build('jenkins-test-project-build', param1 : 'some-
当我使用 where 过滤器通过管道命令排除对象时,它没有给我正确的输出。 PS C:\Users\Administrator> $proall = Get-ADComputer -filter *
我是一名优秀的程序员,十分优秀!