Shell 格式化输出printf、awk


目录
  • Shell 文件的格式化与相关处理 printf、awk
    • 格式化打印printf
      • 案例.格式化输出文件内容
      • 输出命令echo
        • 案例
    • awk数据处理工具
      • 语法格式
      • 处理流程
      • AWK内置变量
        • 条件
      • 高级操作
        • next 跳过当前行
        • if条件判断式
        • 循环

Shell 文件的格式化与相关处理 printf、awk

格式化打印printf

使用场景:将数据格式化输出

语法:printf '打印格式' 实际内容

选项与参数
关于格式方面的几个特殊样式
\n 换行符
\t 水平[tab]按键
\b 后退

%-ns -左对齐,没有则右对齐,输出宽度为n的字符,任何字符都会被显示在 10 个字符宽的字符内,如果不足则自动以空格填充,超过会将内容全部显示出来。
%nd 整型输出
%ni i代表integer,多少位整数
%c 输出一个字符
%N.nf N代表共输出 N 位数,其中n位小数的

说明
1.printf不是管道命令
2.打印格式外面是单双引号都可以
3.格式只指定了一个参数,但多出来的参数仍然会按照该格式输出,格式化字符串会被重用
shell [ranan@hadoop102 ~]$ printf "%s\n" python shell python shell
4.如果没有参数,会用默认值代替,那么%s用null代替,%d用0代替

案例.格式化输出文件内容

[ranan@hadoop102 ~]$ printf "%10s\t %5s\t %5\t \n" $(cat pringtf.txt)

输出命令echo

Shell中的输出命令有两个printf与echo

区别 echo printf
自动添加换行符 ×
设置输出格式 ×

语法:echo [选项] 输出的内容

选项
-n 不要在最后自动换行
-e 进行反斜杠转义,字符串里面出现转义字符将进行转义

案例

输出命令执行结果

echo `date`  #注意是反斜杠

输出内容到文件,文件若不存在则会创建一个文件
> 覆盖写
>> 追加写

echo 123 >> text.txt

echo 输出文件内容
'<'是重定向符,用于改变标准输入的源(从键盘改为文件fileName); 需要输出可以使用cat命令

[ranan@hadoop102 bin]$ echo $(< myhadoop.sh)

awk数据处理工具

sed:一整行的处理
awk:一行分成数个字段来处理,适合小型文本数据

awk 语言的最基本功能是在文件或字符串中基于指定规则浏览和抽取信息,awk 抽取信息后,才能进行其他文本操作,完整的 awk 脚本通常用来格式化文本文件中的信息

语法格式

awk '条件类型1{操作1} 条件类型2{操作2}..' filename

awk可以处理后续接的文件,也可以读取来自前一个命令的标准输出。

注意:这里的引号只能是单引号,awk中变量可以直接使用

处理流程

1.读入第一行,并将第一行的数据写入$0,$1,$2等变量当中
2.根据条件,判断是否需要进行后续的操作
3.完成所有操作和判断
4.重复1~3直到所有数据处理完。

awk是以行为一次处理的单位,字段为最小的处理单位

AWK内置变量

$n:当前记录的第n个字段,比如n为1表示第一个字段,n为2表示第二个字段
$0:表示执行过程中当前行的文本内容
FILENAME : 当前输入文件的名。
NR : 目前awk所处理的第几行数据
NF(Field): 每一行($0)拥有的字段总数
$NF:最后一个Field(列)的数据
FS:目前的列的分隔符,默认是空格

[ranan@hadoop102 ~]$ last -n 5
ranan    pts/0        192.168.10.1     Thu Dec  2 15:56   still logged in
ranan    pts/0        192.168.10.1     Tue Nov 30 19:37 - 10:51  (15:13)
ranan    pts/1        192.168.10.1     Tue Nov 30 15:16 - 19:35  (04:18)
ranan    pts/0        192.168.10.1     Tue Nov 30 10:54 - 16:48  (05:53)
reboot   system boot  4.18.0-240.22.1. Tue Nov 30 10:37   still running

wtmp begins Sun May 23 20:25:21 2021
[ranan@hadoop102 ~]$ last -n 5 | awk '{print $1 "\t" NF "\t最后一列的数据:" $NF}'   
ranan   10      最后一列的数据:in
ranan   10      最后一列的数据:(15:13)
ranan   10      最后一列的数据:(04:18)
ranan   10      最后一列的数据:(05:53)
reboot  10      最后一列的数据:running
        0       最后一列的数据:
wtmp    7       最后一列的数据:2021

print 结尾自动加\n
printf 结尾不加\n

条件

这里我尝试改变FS,以:为分隔符,输出第一个和第二个元素(逗号分隔开),结果这里不太行

[ranan@hadoop102 ~]$ echo $PATH | awk '{print $0}'
/home/ranan/.local/bin:/home/ranan/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/opt/module/jdk1.8.0_212/bin:/opt/module/hadoop-3.1.3/bin:/sbin
[ranan@hadoop102 ~]$ echo $PATH | awk '{FS=":"}{print $1,$2}'
/home/ranan/.local/bin:/home/ranan/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/opt/module/jdk1.8.0_212/bin:/opt/module/hadoop-3.1.3/bin:/sbin

原因是awk执行的流程是
1.读入第一行,并将第一行的数据写入$0,$1,$2等变量当中
2.根据条件,判断是否需要进行后续的操作
3.完成所有操作和判断

意思是改变分隔符之前,第一行使用默认分隔符进行分割了,那么从第二行开始才是以:分割的。

这里可以通过添加条件类型解决,一般使用关系表达式作为条件。

条件类型 条 件 说 明
awk保留字 BEGIN 在 awk 程序一开始,尚未读取任何数据之前执行。BEGIN 后的动作只在程序开始时执行一次
awk保留字 END 在 awk 程序处理完所有数据,即将结束时执行。END 后的动作只在程序结束时执行一次
关系运算符 > 大于
关系运算符 < 小于
关系运算符 >= 大于等于
关系运算符 <= 小于等于
关系运算符 == 等于
关系运算符 != 不等于
关系运算符 A~B 判断字符串 A 中是否包含能匹配 B 表达式的子字符串
关系运算符 A!~B 判断字符串 A 中是否不包含能匹配 B 表达式的子字符串
正则表达式 /正则/ 如果在“//”中可以写入字符,则也可以支持正则表达式

所以我们需要在读入第一行之前,就处理分隔符

[ranan@hadoop102 ~]$ echo $PATH | awk 'BEGIN {FS=":"}{print $1,$2}'
/home/ranan/.local/bin /home/ranan/bin

高级操作

next 跳过当前行

awk中next语句使用:在循环逐行匹配,如果遇到next,就会跳过当前行,直接忽略下面语句。而进行下一行匹配。

awk 'NR%2==1{next}{print NR,$0;}' text.txt

if条件判断式

语法

if(表达式)
动作1
else
动作2

或者if(表达式)动作1;else动作2

[ranan@c105 ~]$ echo x | awk '{if(x>3)print "x大于3";else print"x不大于3" }'
x不大于3

循环

while语法

while (条件)
动作

for循环语法
for (变量;条件;计数器)
动作

动作一句不用加分号
动作多句用分号隔开

continue和break
break 跳出循环
continue 终止当前循环