linux sed awk seq 正则使用 截取字符 之技巧

时间:2023-03-09 17:11:22
linux sed awk seq 正则使用 截取字符 之技巧

[root@room9pc01 ~]# seq 5

1

2

3

4

5

[root@room9pc01 ~]# seq 2 5

2

3

4

5

seq 1 2 10

1

3

5

7

9

[root@desktop0 ~]# seq 10 -2 1

10

8

6

4

2

/etc/profile #定义的系统变量文件

linux sed awk seq 正则使用 截取字符 之技巧

回车:
\n
\r

num=$[RANDOM%100+1]
#0-100
随机数

>
>> 2> 2>> &> &>>

echo
' '
实现输出换行

echo
'ff

>
fffff

>
ff'

ff

fffff

ff

\
可使命令在下一行继续写

[root@desktop0
~]# echo d\

>
d\

>

dd

[root@svr5
~]#
test=11

[root@svr5
~]#
echo ${test}RMB
//区分后可以识别

11RMB

[root@svr5
~]#
unset test //撤销变量test

a="ab
d"

a='$abc'
单引号可以屏蔽特殊符号的功能

`
` 等同
$(
)

将回显功能关闭(stty
-echo),开启后用户在屏幕上输出是看不到的

*将回显功能恢复(stty
echo)。

使用export发布全局变量

默认情况下,自定义的变量为局部变量,只在当前Shell环境中有效,而在子Shell环境中无法直接使用。比如已定义的SCHOOL变量,当进入到sh或bash子Shell后,变量SCHOOL将处于未定义的状态:

[root@svr5
~]#
export
yy //发布已定义的变量

[root@svr5
~]#
export
XX="1234"//发布新变量

env可查看所有环境变量:

set可查看所有变量(包括env能看到的环境变量):

全局文件为/etc/profile,对所有用户有效;用户文件为~/.bash_profile,仅对指定的用户有效。

PS1表示Shell环境的一级提示符,即命令行提示符(\u
用户名、\h
主机名、\W
工作目录、\$
权限标识):

PS2表示二级提示符,出现在强制换行、at任务编辑等场合:

[root@svr5
~]#
vim location.sh

!/bin/bash

echo
$0//脚本的名称
如果用 .
或者
source
当前shell执行
显示 shell名称

echo
$1//第一个参数

echo
$2//第二个参数

echo
$*//所有参数

echo
$# //用户
输入的参数总个数

echo
$$ //当前进程的进程号

echo
$?//上一个程序的返回状态码

[root@svr5
~]#
chmod +x
location.sh
//添加可执行权限

整数运算工具
expr
$[9+9] let

  1. [root@svr5
    ~]#
    X=1234//定义变量X

  2. [root@svr5
    ~]#
    expr $X +78//加法

  3. 1312

  4. [root@svr5
    ~]#
    expr $X -78//减法

  5. 1156

  6. [root@svr5
    ~]#
    expr $X \*78//乘法,操作符应添加\转义

  7. 96252

  8. [root@svr5
    ~]#
    expr $X /78//除法,仅保留整除结果

  9. 15

  10. [root@svr5
    ~]#
    expr $X %78//求模

  11. 64

let
X;
echo $X # X(X=X+78)

x=$[5*6]

echo
$]

echo
$[RANDOM%10] #0~9之间的随机数

echo
"scale=3;10/3" | bc
#指定小数位数

echo
"1+1" | bc

------------------------------------------let
可以进行赋值运算let
x=x+1或者let
x+=1或者let
x++

-------------------------------------------x=$[x+2]

字符
==
!=
-z #-z判断是否为空

数字
-eq
-ne -ge -gt -le -lt

文件
-e
-f -d -r -w -x

[-e
"/etc/fstab"]&&
echo "存在"||
echo "不存在"

[-r
"/tmp/test.txt"]&&
echo "可读"||
echo "不可读"

#是否可读是对当前用户来说的

#权限判断是对当前用户来说的

逻辑与
&&

逻辑或
||
逻辑判断也遵循匹配即停止

[root@desktop0
~]# echo {1..3} #不支持变量{1..$x}
错误

1
2 3

[root@desktop0
~]# seq 3

1

2

3

[root@desktop0
~]# x=3

[root@desktop0
~]# seq $x
#支持变量

1

2

3

[root@server0
opt]# seq 6 9

6

7

8

9

!/bin/bash

for
i in `seq $1` #seq
是命令
所以需要``括起来

do

echo
第${i}次
#{}是一种格式
代表括号内的一段数字 不需要 `
`

done

  1. [root@svr5
    ~]# vim test.sh

#!/bin/bash

case
$1 in

redhat|xiaoming|lisi)
# |
满足其中一个即可

echo
"fedora";;

fedora)

echo
"redhat";;

*)

//默认输出脚本用法

echo
"用法:
$0 {redhat|fedora}"

esac

A
&& B //仅当A命令执行成功,才执行B命令

A||B
//仅当A命令执行失败,才执行B命令

A;
B //执行A命令后执行B命令,两者没有逻辑关系

A&&
B || C //先运算A&&
B 都成立就不会执行C
否则就执行C

[root@svr5
~]#
var1="nb";
var2=""

[root@svr5
~]#
[-z
"$var1"]&&
echo "空值"||
echo "非空值"
# -z判断是否是空值

非空值

#-n非空值为真

[root@svr5
~]#
[-z
$var2 ]&&
echo "空值"||
echo "非空值"

空值
//变量var2已设置,但无任何值,视为空

[root@svr5
~]#
[!-z
$var1 ]//测试var1是否为非空

vim
cd

!/bin/bash

cd
/opt

[root@desktop0
~]# bash
/root/cd #开启新进程
执行之后 退出

[root@desktop0
~]#
. /root/cd
#不开启新进程

[root@desktop0
opt]#

!/bin/bash

mycd(){

echo
$1

}

mycd
lisi

echo
$1

[root@desktop0
~]# . /root/cd zhangsan
#两个$1的区别

lisi

zhangsan

扩展的echo使用\033[固定格式,34m是颜色
0m是屏幕后面的输出恢复默认颜色

echo
-e "\033[34m里斯\033[0m"

[root@room9pc01
~]# i=0

[root@room9pc01
~]# let i++ && echo $i

[root@room9pc01
~]# i=0

[root@room9pc01
~]# let i++ || echo $i # let 变量初始值是0时,let
i++ 退出时状态时非0

1

[root@room9pc01
~]# let g++

[root@room9pc01
~]# echo $?

1

[root@room9pc01
~]# echo $g

1

if
[ $JF -ge 90 ]
; then

echo
"$JF 分,神功绝世"

elif
[
$JF -ge 60 ]
; then

echo
"$JF 分,略有小成"

else

echo
"$JF 分,初学乍练"

fi

for
i in {1..100} 或者
`seq
100` 或者
`cat
/opt/user.txt` #可以是数字和文本

do

循环内容

done

while
[ 判断
]
#拓展
while

无限循环

do

循环内容

let
i++
#可通过改变判断条件的值
实现有限循环

done

case
变量
in

模式1)

执行指令;;

模式2)

执行指令;;

*)
//默认输出脚本用法

执行命令;;

esac

函数名(){

命令序列

....

}

function函数名
{

命令序列

....

}

Shell版本的fork炸弹

.(){

.|.&

}

.

截取字符串
空格也算一个字符 a="ab
cd e"

echo
${#a} #字符长度

7

${变量名:起始位置:长度}

expr
substr "$变量名"
起始位置
长度

echo
$变量名
|
cut -b 起始位置-结束位置

[root@desktop0
~]# a=abcdef

[root@desktop0
~]# echo ${a:1:3}
从序号1开始位

位置从0开始

bcd

[root@desktop0
~]# echo ${a:0:3}
从序号0开始位

abc

[root@desktop0
~]# echo ${a::3}
0可以省略

abc

[root@desktop0
~]# echo $a | cut
-b 1 截第1位
位置 从1开始

a

[root@desktop0
~]# echo $a | cut
-b 2-3 截第2位

bc

# -3 截开头到第三
3-
第三到结尾

[root@desktop0
~]# expr
substr $a 2 3 从序号2开始位

位置从1开始

bcd

[root@desktop0
~]# expr substr $a 1

expr:
语法错误

[root@desktop0
~]# expr substr $a 1 1

a

[root@desktop0
~]# echo ${a:1:1}

b

字符串拼接[root@server0
~]# a=q #数字也可以拼接
正常纯数字 还可以计算

[root@server0
~]# b=w

[root@server0
~]# c=$c$a$b

[root@server0
~]# echo $c

qw

字符串查找并替换

只替换第一个匹配结果:${变量名/old/new}

替换全部匹配结果:${变量名//old/new}

[root@server0
~]# a=`cat /etc/passwd | head -1`

[root@server0
~]# echo $a

root:x:0:0:root:/root:/bin/bash

[root@server0
~]# b=${a/root/jjjj};echo
$b 一个/
只替换第一个目标字符串

jjjj:x:0:0:root:/root:/bin/bash

[root@server0
~]# b=${a//root/jjjj};echo
$b 两个/替换全部目标字符串

jjjj:x:0:0:jjjj:/jjjj:/bin/bash

[root@server0
~]# b=${a//root/};echo $b

:x:0:0::/:/bin/bash

字符串查找并删除

a=root:x:0:0:root:/root:/bin/bash

从左开始查找:掐头
从开头匹配

${a#root}
找到第一个目标即停止,从开头匹配如果左起第一个不是root,代表没有匹配项

${a##oot}
从开头匹配(开头匹配不上即停止),删掉一层,继续匹配,找到所有目标(像扒皮一样删除)

${a#*t}
*是通配符,找到第一个*t
,即停止

${a##*t}
一直找到最后一个*t
,把头全删掉

从右开始查找:去尾

${a%root}
从右开始查找,%只删除一层

${a%%root}
%%扒皮查找

${a%root*}

${a%%root*}

a=root:x:0:0:root:/root:/bin/bash

[root@server0
~]# echo ${a#ro}

ot:x:0:0:root:/root:/bin/bash

[root@server0
~]# echo ${a#oo}

root:x:0:0:root:/root:/bin/bash

备用值

x=f

x=${x:-123}

#当x已经被赋值时,备用不会生效{备用值

[root@server0
opt]# echo $x

f

计算1到n的求和,如果用户无输入时,则n为1

!/bin/bash

read
-p "qiuhe:" p

p=${p:-1}
# 备用值

for
i in `seq $p`

do

let
x+=i

done

echo
$x

基本正则列表

正则符号

描述

^

匹配行首

$

匹配行尾

[
]

集合,匹配集合中的任意单个字符

[^]

对集合中单个字符取反

.

匹配任意单个字符(代表一个字符)

*

匹配一个字符任意次数

\{n,m\}

匹配一个字符n到m次

\{n\}

匹配一个字符n次

\{n,\}

匹配一个字符n次以上

\(\)

保留

扩展正则表达式

正则符号

描述

+

一个字符最少匹配一次

一个字符最多匹配一次

{n,m}

一个字符匹配n到m次
等价与 \{n,m\}

(
)

组合为整体。保留(代表一个字符
匹配)

|

或者
a|b
等价与
[ab]

\b

单词边界(\broot\b,代表匹配root两边是空)

[root@svr5
~]#
grep HISTSIZE /etc/profile

HISTSIZE=1000

*清空历史的命令。

[root@svr5
~]#
history -c
//清空自己的历史命令

[root@svr5
~]#
>~/.bash_history
//清空记录文件

sed
支持管道
正则条件要放在//内

  • 条件可以是行号或者/正则/

  • 没有条件时,默认为所有条件

  • 指令可以是增、删、改、查等指令

  • 默认sed会将所有输出的内容都打印出来,可以使用-n屏蔽默认输出

  • 选项中可以使用-r选项,让sed支持扩展正则

  • -n(屏蔽默认输出,默认sed会输出读取文档的全部内容)

  • -r(让sed支持扩展正则)

  • -i(sed直接修改源文件,默认sed只是通过内存临时修改文件,源文件无影响)

  • 指令:
    p
    d s i a c r w

sed
[-选项]
'/定位筛选条件/指令
'
文件
#选项可省略,定位筛选条件支持正则(定位到那一行)

sed
'' abc.txt #会默认输出文件内容
逐行显示

sed
-n '' abc.txt #-n 取消默认输出

sed
-n 'p' abc.txt #命令p(print)输出全部,逐行显示

sed
-n '3p' abc.txt #输出第三行

sed
-n '1,2p abc.txt #输出第1到第2行

sed
-n '1,+2p' abc.txt #输出第1行
加后面两行

sed
-n '1p;3p' abc.txt #第一和第三行,
;
隔开命令

sed
-n '/root/p' /etc/passwd #输出筛选结果
格式:/筛选条件
/
支持正则筛选

sed
-n '1~2p' abc.txt #输出第一行
~连续跳步
继续输出跳步所在的行(实现只输出奇数行)

sed
-n '$='
a.txt //输出文件的行数

sed
'/991/d' abc.txt #d删除
用法同p

sed
'/xml/d'
a.txt
//删除所有包含xml的行

sed
'/xml/!d' a.txt //删除不包含xml的行,!符号表示取反

sed
'$d' a.txt //删除文件的最后一行

sed
'/^$/d' a.txt //删除所有空行(没有空格的行)

sed
''
abc.txt #s替换

#
:只处理第二行,没有时
逐行处理
:每一行的第3个old,没有参数时,只替换第一个old

sed
's/old/new/g'
abc.txt

#

g每一行的所有old

sed
-n 's/2017/xxxx/p' test.txt
#p只输出定位处理的那一行

替换操作的分隔“/”可改用其他字符,如#、&等,便于修改文件路径

sed
's#/bin/bash#/sbin/sh#'
a.txt
//将/bin/bash替换为/sbin/sh

sed
's/\/bin\/bash/\/sbin\/sh/' b.txt

sed
'4,7s/^/#/'
a.txt
//将第4~7行注释掉(行首加#号)

sed
's/^#an/an/'
a.txt
//解除以#an开头的行的注释(去除行首的#号)

sed
'/kk/s/123/***/' shiyan #将匹配kk的那行进行替换

123

123

123

123

kkk***

[root@svr5
~]#
sed -r
's/^(.)(.*)(.)$/\3\2\1/'
nssw.txt
#将文件中每行的第一个、倒数第1个字符互换

sed
-r
's/([A-Z])/[\1]/g'
nssw.txt
#为文件中每个大写字母添加括号

[root@server0
~]# sed -n '/^root/,+2p'
/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

[root@server0
~]# cat aaa

1

2

3

4

[root@server0
~]# sed -r "1h;2g" aaa #数字是指定行,没有数字
代表所有行

1

1

3

4

[root@server0
~]# sed -r "1H;2G" aaa #粘贴板中默认有一空行

1

2

1

3

4

h,H复制制定行行到粘贴板,h是覆盖到粘贴板,H是追加的到粘贴板,g是将指定行覆盖粘贴,G是在指定行追加粘贴。粘贴板是内存不是硬盘

$
cat foo

11111111111111

22222222222222

33333333333333

$
sed '1!G;h;$!d' foo

33333333333333

22222222222222

11111111111111

$
sed -n '1!G;h;$p' foo

33333333333333

22222222222222

11111111111111

将模式空间的内容保存到保持空间中去

sed
中的
d
表示删除模式空间。

1!G表示除了第一行以外,其余行都执行G命令;$!d表示除了最后一行以外,其余行都执行d命令。

看一下sed
'1!G;h;$!d'命令执行过程中保持空间与模式空间的变化:

命令
保持空间 模式空间

第一行
h;d
执行前:null
执行后:1111\n
执行前:1111\n
执行后:null

第二行
G;h;d
执行前:1111
执行后:2222\n1111\n
执行前:2222\n
执行后:null

第二行
G;h
执行前:2222\1111\n
执行后:3333\n2222\n\1111\n
执行前:3333\n
执行后:3333\n2222\n\1111\n

*sed工具的多行文本处理操作:

  • i:
    在指定的行之前插入文本

  • a:在指定的行之后追加文本

  • c:替换指定的行

  1. [root@svr5
    ~]#
    sed '2a
    XX'
    a.txt
    //在第二行后面,追加XX

  2. [root@svr5
    ~]#
    sed '2i
    XX'
    a.txt
    //在第二行前面,插入XX

  3. [root@svr5
    ~]#
    sed '2c
    XX'
    a.txt
    //将第二行替换为XX

sed
-i
'$a
192.168.4.5 svr5.tarena.com svr5'/etc/hosts
#在最后一行后
追加

r
读取文件
动作结合 -
选项才会存入
否则只会输出

w保存到文件
动作会直接以覆盖 的方式另存为新文件

sed
-r "1r bbb" aaa #读取bbb文件,在aaa文件的第一行后插入bbb文件内容

sed
-r "r bbb" aaa #在aaa文件的每一行后插入
r制定行的用法同p
,加上选项
-i

aaa文件即改变

sed
-r "1w bbb" aaa #将aaa文件的第一行写入bbb文件,没有bbb文件会自动创建,
aaa文件不变
r
指定行用法同p

*总结知识点:

sed
[选项]
'条件指令'
文件

*选项:

*-n
屏蔽默认输出

*-r
支持扩展正则

*-i
修改源文件

*条件:

*行号
4
4,5 4~2 4,+10

*/正则/

*指令:

*p
打印

*d
删除

*s
替换s/旧/新/g

*a
追加

*i
插入

*c
替换行

less

cat

grep
egrep

sed

awk

awk
正则匹配条件要放在//内
同sed

匹配条件都是筛选出行然后再对行进行操作,awk中的变量(大括号内的变量)和shell中的不能互相调用,筛选条件的变量可以是shell中的变量

!/bin/bash

用文本编写好的密码和用户创建

read
-p "请输入一个编写好的用户和密码文本名词:"
Wb

a=`awk
'{print $1}' $Wb`

for
i in $a

do

useradd
$i

b=$(awk
'/'$i'/{print
$2}' $Wb)

echo
$b | passwd --stdin $i

done

awk
[选项]
'[条件]{指令}'
文件
支持管道

[root@svr5
~]#
awk '{print
$1,$3}'
test.txt
列和第3列
若未指定分隔符,则默认将空

格、制表符等作为分隔符

awk
-F:'{print
$1,$7}'/etc/passwd
#-F可指定分隔符可以是任意字符串,
分隔符是不可以print的(但

#没有指定输出列
分隔符是可以输出的)

awk
-F
[:/]
'{print $1,$10}' /etc/passwd
#[]中的任意单个字符都是分隔符

*awk常用内置变量:

*$0
文本当前行的全部内容

*$1 文本的第1列

*$2 文件的第2列

*$3 文件的第3列,依此类推

*NR 文件当前行的行号(相当与一个信号,正在处理哪一行即NR就是当前行的行号)

*NF 文件当前行的列数(有几列)

awk
-F:'{print
$1,"的解释器:",$7}'/etc/passwd

ifconfig
eth0 |
awk '/TX
p/{print
$5}'//过滤发送数据的流量#正则匹配所需行

[root@svr5
~]#
df -h
/

文件系统
容量 已用 可用 已用%挂载点

/dev/sda2
19G .2G
11G %/

[root@svr5
~]#
df -h
|
awk '/\/$/{print
$4}' #注意转义/

11G

BEGIN{}
ENG{}

  • BEGIN{
    } 行前处理,读取文件内容前执行,指令执行1次

  • {
    } 逐行处理,读取文件过程中执行,指令执行n次

  • END{
    } 行后处理,读取文件结束后执行,指令执行1次

awk
[选项]'
BEGIN{指令}
{指令}
END{指令}'文件

[root@server0
~]# awk 'BEGIN{print "a"}'
#输出字符
要用双引号

a

#BEGIN{}处理命令跟文件无关,可以不加处理文件

[root@server0
~]# awk 'BEGIN{print a=1,a}'
#不用双引号
代表引用变量

1
1

[root@server0
~]# awk 'BEGIN{print a=1;print
a}'

1

1

[root@server0
~]# cat aaa

1

2

3

4

[root@server0
~]# awk '{print ++a}' aaa #{}处理命令跟文件有关,逐行匹配,匹配成功便执行命令

1

2

3

4

[root@server0
~]# awk 'END{print 2}' aaa #END{}最后处理
结构同BEGIN{},与文件aaa无关

2
#(但不可以省略aaa因为BEGIN是过滤文件之前操作,而END是过滤文件之后操作

awk
'BEGIN{print A=1}{print
A++}END{print
A+1}' aaa #++A A++ 同C语言

1

1

2

3

4

6

[root@server0
~]# awk 'BEGIN{print A=1}{print
++A}END{print
A+1}' aaa

1

2

3

4

5

6

seq
5 | awk '$1%3'
#条件筛选的作用同sed
目的是找出匹配的行
而真假同C语言,0假,非0真

1

2

4

5

seq
5 | awk '$1%3==0'

3

seq
|
awk '$1%7==0||$1~/7/'
列出100以内整数中7的倍数或是含7的数:

[root@svr5
~]#
awk 'BEGIN{x=0}/bash$/{x++}
END{print x}'/etc/passwd

29

使用“\t”显示Tab制表位

[root@svr5
~]#
awk -F:'/^(root|adm)/{print
$1,$3}'/etc/passwd
#输出root或adm账户的用户名和UID

#
信息:

awk
-F:'$1~/root/'/etc/passwd
#输出账户名称包含root的基本信息(第1列匹配包含root)

awk
-F:'$7!~/nologin$/{print
$1,$7}'/etc/passwd
#对第7个字段做!~反向匹配输出其中登录Shell不

#以nologin结尾

*使用数值/字符串比较设置条件

*比较符号:==(等于)
!=(不等于)
>(大于)

*>=(大于等于)
<(小于)
<=(小于等于)

*awk
-F:'NR==3{print}'/etc/passwd
#输出第3行(行号NR等于3)的用户记录:

awk
-F:'$3>=1000{print
$1,$3}'/etc/passwd

awk
-F:'$1=="root"'/etc/passwd
#输出用户名为“root”的行:

awk
-F:'$3>10
&&
$3<20'/etc/passwd

awk
-F:'$3>1000
|| $3<10'/etc/passwd

awk
'BEGIN{x=8;x--;print
x}'

if(条件){指令}

if(条加){指令}else{}

if(条件){指令}else
if{条件}......else{指令}

awk
-F:'{if($3>1000){i++}}END{print
i}'/etc/passwd
#统计/etc/passwd文件中UID大于1000的用户

#
个数:

awk
-F:'{if($3<=1000){i++}else{j++}}END{print
i,j}'/etc/passwd

*awk数组

*1)数组的语法格式

*数组是一个可以存储多个值的变量,具体使用的格式如下:

*定义数组的格式:数组名[下标]=元素值

*调用数组的格式:数组名[下标]

*遍历数组的用法:for(i
in
数组名){print
数组名[变量]}。#i的值是下标
类似python的字典(因为其下标是可以任意定义的字符串(字母数字下划线))

awk
'BEGIN{a[0]=11;a[1]=88;print
a[1],a[0]}'

[root@svr5
~]#
awk 'BEGIN{a[0]=0;a[1]=11;a[2]=22;
for(i in a){print i,a[i]}}'

针对文本排序输出可以采用sort命令,相关的常见选项为-r、-n、-k。其中-n表示按数字顺序升序排列,而-r表示反序,-k可以指定按第几个字段来排序。

[root@room9pc01
~]# cat aaa

a

a

b

b

a

a

a

v

[root@room9pc01
~]# awk '{pi[$1]++} END{for(i in pi){print pi[i],i}}' aaa
#计算文本中相同字段

出现的次数

1
v

5
a

2
b

[root@room9pc01
~]# awk '{pi[$1]++} END{for(i in pi){print pi[i],i}}' aaa | sort -nr

5
a

2
b

1
v