2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > 【Shell牛客刷题系列】SHELL21 格式化输出:来看个printf命令的小彩蛋~

【Shell牛客刷题系列】SHELL21 格式化输出:来看个printf命令的小彩蛋~

时间:2022-09-30 04:40:49

相关推荐

【Shell牛客刷题系列】SHELL21 格式化输出:来看个printf命令的小彩蛋~

该系列是基于牛客Shell题库,针对具体题目进行查漏补缺,学习相应的命令。

刷题链接:牛客题霸-Shell篇。

该系列文章都放到专栏下,专栏链接为:《专栏:Shell》。欢迎关注专栏~

本文知识预告:

本文首先学习了printf命令地用法;然后,给出了五种题目的解决方案,涉及到了awksedxargsprintf命令地用法,其次,对于本题用到的printf的一个小彩蛋也是比较有意思的。

题目:SHELL21 格式化输出

有一个文件nowcoder.txt,里面的每一行都是一个数字串,编写一个shell脚本对文件中每一行的数字串进行格式化:每3个数字加入一个逗号(,)。例如:数字串为“123456789”,那么需要格式化为123,456,789。

假设nowcoder.txt内容如下:

1121231234

那么你的脚本输出如下:

1121231,234123,456

基本命令学习

sed:批量编辑文本文件

sed命令来自于英文词组“stream editor”的缩写,其功能是用于利用语法/脚本对文本文件进行批量的编辑操作。sed命令最初由贝尔实验室开发,后被众多Linux系统接纳集成,能够通过正则表达式对文件进行批量编辑,让需要重复的工作不再浪费时间。

sed是非交互式的编辑器。它不会修改文件,除非使用shell重定向来保存结果。默认情况下,所有的输出行都被打印到屏幕上。sed编辑器逐行处理文件(或输入),并将结果发送到屏幕。

sed命令行格式为:

sed [-nefri] ‘command’ 输入文本

常用选项:

-n:使用安静(silent)模式。在一般sed的用法中,所有来自 STDIN的资料一般都会被列出到萤幕上。但如果加上-n参数后,则只有经过sed特殊处理的那一行(或者动作)才会被列出来。-e:直接在指令列模式上进行sed的动作编辑;-f:直接将sed的动作写在一个档案内,-f filename则可以执行filename内的sed动作;-rsed的动作支援的是延伸型正规表示法的语法。(预设是基础正规表示法语法)-i:直接修改读取的档案内容,而不是由萤幕输出。

常用命令:

a:新增,a的后面可以接字串,而这些字串会在新的一行出现;c:取代,c的后面可以接字串,这些字串可以取代n1,n2之间的行;d:删除,因为是删除,所以d后面通常不接任何字符;i:插入,i的后面可以接字串,而这些字串会在新的一行出现(目前的上一行);p:列印,亦即将某个选择的资料印出。通常p会与参数sed -n一起运作;s:取代,可以直接进行取代的工作!通常这个s的动作可以搭配正规表示法!例如1,20s/old/new/gg:是行内进行全局替换

常用参数:

参考实例

查找指定文件中带有某个关键词的行:

lucky@DESKTOP-VQ8KID4:~/shell$ sed -n '/main/p' nowcoder.txtint main()

替换指定文件中某个关键词成大写形式:

lucky@DESKTOP-VQ8KID4:~/shell$ sed 's/int/INT/g' nowcoder.txt#include <iostream>using namespace std;INT main(){INT a = 10;INT b = 100;cout << "a + b:" << a + b << endl;return 0;}

有点巧,这和前面学的Vim里面的替换基本一样。

读取指定文件,删除所有带有某个关键词的行:

lucky@DESKTOP-VQ8KID4:~/shell$ sed '/int/d' nowcoder.txt#include <iostream>using namespace std;{cout << "a + b:" << a + b << endl;return 0;}

读取指定文件,在第4行后插入一行新内容:

lucky@DESKTOP-VQ8KID4:~/shell$ sed -e '4a\ cout << "hello world" << end;' nowcoder.txt#include <iostream>using namespace std;int main(){cout << "hello world" << end;int a = 10;int b = 100;cout << "a + b:" << a + b << endl;return 0;}

读取指定文件,在第4行后插入多行新内容:

lucky@DESKTOP-VQ8KID4:~/shell$ cat nowcoder.txt | sed -e '4a\ cout << "hello world"<< endl; \n cout << "hello aha" << endl;'#include <iostream>using namespace std;int main(){cout << "hello world" << endl;cout << "hello aha" << endl;int a = 10;int b = 100;cout << "a + b:" << a + b << endl;return 0;}

读取指定文件,删除第2-5行的内容:

lucky@DESKTOP-VQ8KID4:~/shell$ cat -n nowcoder.txt | sed '2,5d'1 #include <iostream>6int b = 100;7cout << "a + b:" << a + b << endl;8return 0;9 }

读取指定文件,替换第2-5行的内容:

lucky@DESKTOP-VQ8KID4:~/shell$ sed '2,5c cout << "gaga" << endl;' nowcoder.txt#include <iostream>cout << "gaga" << endl;int b = 100;cout << "a + b:" << a + b << endl;return 0;}

指定读取某个文件的第3-7行:

lucky@DESKTOP-VQ8KID4:~/shell$ sed -n '3,7p' nowcoder.txtint main(){int a = 10;int b = 100;cout << "a + b:" << a + b << endl;

awk:文本和数据进行处理的编程语言

awk命令来自于三位创始人”Alfred Aho,Peter Weinberger, Brian Kernighan “的姓氏缩写,其功能是用于对文本和数据进行处理的编程语言。使用awk命令可以让用户自定义函数或正则表达式对文本内容进行高效管理,与sedgrep并称为Linux系统中的文本三剑客。

语法格式awk 参数 文件

常用参数

常用的awk内置变量

awk语法由一系列条件和动作组成,在花括号内可以有多个动作,多个动作之间用分号分隔,在多个条件和动作之间可以有若干空格,也可以没有。

awk是一种处理文本文件的编程语言,文件的每行数据都被称为记录默认以空格或制表符为分隔符每条记录被分成若干字段(列)awk每次从文件中读取一条记录

例子:

仅显示指定文件中第1、2列的内容(默认以空格为间隔符):

lucky@DESKTOP-VQ8KID4:~/shell$ awk '{print $1,$2}' nowcoder.txt#include <iostream>using namespaceint main(){int aint bcout <<return 0;}

以冒号为间隔符,仅显示指定文件中第1列的内容:

lucky@DESKTOP-VQ8KID4:~/shell$ awk -F : '{print $1,$2}' /etc/passwdroot xdaemon xbin x...tcpdump xsshd xlandscape xpollinate xlucky x

/etc/passwd文件中的内容由:分隔开。

以冒号为间隔符,显示系统中所有UID号码大于500的用户信息(第3列):

lucky@DESKTOP-VQ8KID4:~/shell$ awk -F : '$3>=500' /etc/passwdnobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologinlucky:x:1000:1000:,,,:/home/lucky:/bin/bash

仅显示指定文件中含有指定关键词main的内容:

lucky@DESKTOP-VQ8KID4:~/shell$ awk '/main/{print}' nowcoder.txtint main()

以冒号为间隔符,仅显示指定文件中最后一个字段的内容:

lucky@DESKTOP-VQ8KID4:~/shell$ awk -F : '{print $NF}' /etc/passwd/bin/bash/usr/sbin/nologin/usr/sbin/nologin.../usr/sbin/nologin/bin/false/bin/bash

输出行号,NR将所有文件的数据视为一个数据流,而FNR则是将多个文件的数据视为独立的若干个数据流,遇到新文件时行号从1开始重新递增。

lucky@DESKTOP-VQ8KID4:~$ awk '{print NR}' first.txt three.sh123lucky@DESKTOP-VQ8KID4:~$ awk '{print FNR}' first.txt three.sh112

xargs:给其他命令传参数的过滤器

xargs命令来自于英文词组” extended arguments“的缩写,其功能是用于给其他命令传参数的过滤器xargs命令能够处理从标准输入管道符输入的数据,并将其转换成命令参数,也可以将单行或多行输入的文本转换成其他格式

xargs命令默认接收的信息中,空格是默认定界符,所以可以接收包含换行和空白的内容

语法格式:xargs [参数]

常用参数:

参考实例

默认以空格为定界符,以多行形式输出文件内容,每行显示一三段内容值:

lucky@DESKTOP-VQ8KID4:~$ cat nowcoder.txt | xargs -n 1howtheyareimplementedandappliedincomputer

指定字符X为定界符,默认以单行的形式输出字符串内容:

lucky@DESKTOP-VQ8KID4:~$ echo "FirstXSecondXThirdXFourthXFifth" | xargs -dXFirst Second Third Fourth Fifth

定字符X为定界符,以多行形式输出文本内容,每行显示两段内容值:

lucky@DESKTOP-VQ8KID4:~$ echo "FirstXSecondXThirdXFourthXFifth" | xargs -dX -n 2First SecondThird FourthFifth

设定每一次输出信息时,都需要用户手动确认后再显示到终端界面:

lucky@DESKTOP-VQ8KID4:~$ echo "FirstXSecondXThirdXFourthXFifth" | xargs -dX -n 2 -pecho First Second ?...yFirst Secondecho Third Fourth ?...yThird Fourthecho 'Fifth'$'\n' ?...n

printf:shell 输出

printf命令模仿 C 程序库(library)里的printf()程序。

printf使用引用文本或空格分隔的参数,外面可以在printf中使用格式化字符串,还可以制定字符串的宽度、左右对齐方式等。默认printf不会像echo自动添加换行符,我们可以手动添加\n

语法格式:printf [格式控制字符串] [参数]

常用参数:

参考实例

字符串输出:

lucky@DESKTOP-VQ8KID4:~$ printf "Hello, Shell\n"Hello, Shell

下面用一个脚本来体现printf的强大功能:

lucky@DESKTOP-VQ8KID4:~$ cat printf.shprintf "%-10s %-8s %-4s\n" 姓名 性别 体重kgprintf "%-10s %-8s %-4.2f\n" 郭靖 男 66.1234printf "%-10s %-8s %-4.2f\n" 杨过 男 48.6543printf "%-10s %-8s %-4.2f\n" 郭芙 女 47.9876

执行脚本,输出结果如下所示:

lucky@DESKTOP-VQ8KID4:~$ bash printf.sh姓名性别 体重kg郭靖男66.12杨过男48.65郭芙女47.99

解释:

%s%c%d%f都是格式替代符%-10s指一个宽度为10个字符(-表示左对齐,没有则表示右对齐),任何字符都会被显示在10个字符宽的字符内,如果不足则自动以空格填充,超过也会将内容全部显示出来。%-4.2f指格式化为小数,其中.2指保留2位小数。 格式控制字符串为双引号:

lucky@DESKTOP-VQ8KID4:~$ printf "%d %s\n" 1 "abc"1 abc

格式控制字符串为单引号:

lucky@DESKTOP-VQ8KID4:~$ printf '%d %s\n' 1 "abc"1 abc

没有引号也可以输出:

lucky@DESKTOP-VQ8KID4:~$ printf %s abcdefabcdef

本题可以使用printf命令的一个小彩蛋解决:

printf "%'d\n" $i

%d前面的单引号是给英文数字中千位加分割符的,只要是数字类型都行

题目解决方案

方法一:awk

awk 'BEGIN{FS = ""}{for(i = 1; i <= NF; i++) {if((NF - i) % 3 == 0 && i != NF) printf $i",";else printf $i};printf "\n"}' nowcoder.txt

下面这种写法也可以:

awk -F "" '{ret="";for(i = 1; i <= NF; i++){ret = ret $i;if(i % 3 == NF % 3 && i != NF)ret=ret ","} print ret}'

方法二:sed+正则

注意:\>是匹配一个零宽的单词边界,这是gnu sed的扩展支持。

sed -E ':a; s/([[:digit:]])([[:digit:]]{3})\>/\1,\2/; ta' nowcoder.txt

方法三:while

while read line; dok=0lin_len=${#line}str=""for ((i = $lin_len - 1; i >= 0; i--)); dok=$(($k + 1))str="${line:$i:1}$str"if [ $(($k % 3)) -eq 0 ] && [ $i -gt 0 ] && [ $lin_len -gt 3 ]; thenstr=",$str"fidoneecho ${str}done <nowcoder.txt

方法四:for+printf

%d前面的单引号是给英文数字中千位加分割符的,只要是数字类型都行,想要在千位加英文中的分割符,就加个',所以这个里面也可以改成printf "%'.f\n" $i

for i in $(cat nowcoder.txt); doprintf "%'d\n" $idone

当然,用while也行,一个意思:

while read line; doprintf "%'d\n" ${line}done <nowcoder.txt

方法五:xargs+printf

cat nowcoder.txt | xargs -n1 printf "%'d\n"

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。