bash5----进阶2 操作字符串
1、命令expr : evaluate expressions(支持模式匹配和字符串操作。字符串表达式的优先级高于数值表达式和逻辑关系表达式。)
SYNOPISIS
expr EXPRESSITONS
expr OPTION
expr ARG1 {+ - * / | & < <= > >= != %} ARG2
expr STRIGN : REGEXP == expr match "STRING" 'REGEXP' (如果成功返回匹配到的字数,也可以用于计算字符串长度)
substr STRING POS(postion) LENGTH (提取子串见2)
index STRING CHARS #类似于C里面的strchr,当见到第一个字符,即返回字节数
length STRING (字符串长度见下文)
+ TOKEN:将TOKEN解析为普通字符串,即使TOKEN是像MATCH或操作符"/"一样的关键字。这使得'expr length + "x" : '.*/''可以正常被测试,即使"$x"的值可能是'/'或'index'关键字。这个操作符是一个GUN扩展。
更多的详细内容可以看大佬博文。
字符串长度:法1:echo `expr length $Stringname`
法2:echo ${#Stringname}
法3:echo `expr "Stringname" : '.*'
抄个例子,在一个文本文件的段落之间插入空行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | #!/bin/bash # paragraph-space.sh # 在一个单倍行距的文本文件中插入空行. # Usage: $0 <FILENAME MINLEN=45 # 可能需要修改这个值. # 假定行的长度小于$MINLEN所指定的长度的时候 #+ 才认为此段结束. while read line # 提供和输入文件一样多的行... do echo "$line" # 输入所读入的行本身. len=${ #line} if [ "$len" -lt "$MINLEN" ] then echo # 在短行(译者注: 也就是小于$MINLEN个字符的行)后面添加一个空行. fi done exit 0 |
这个是书本上的例子,很显然不能直接执行,不过给我们提供了一个思路。如何给段落(长度小于45的段落)中间添加空行
首先还是需要明白read这个函数的用法:
首先 shell里面的read 和函数read还是不一样的,一个是从stdio中读取,一个是高级编程中常用的函数。我们通常使用man read 的这个read看到的是unistd.h里面的read函数。如果想看到shell中read的用法 通常使用read --help(我姑且这么认为,有问题欢迎大家评论批评)。
那么"read --help"是这么描述的:
read: read [-ers] [-a array] [-d delim] [-i text] [-n nchar] [-p prompt] [-t timeout] [-u fd] [name ...]
:-a 后面参数是数组。-d 分隔符换成 delim,并根据 'delim'来分行 而不是回车。-n后面接数字,定义输入文本长度。-p 后面接PROMPT作为输出提示信息。 -t 后面接秒数,代表等待时间。-u 从fd中读入。
Read a line from the standard input and split it into fields.
上面是把stdin在command line 用 '<' 重定向到FILENAME中,然后用echo来输出到stdout里面。
下面有几种变化方式,来将他变形一下:
1、可以把上面第11行while read line 改成 cat FILENAME(也可以用绝对路径) | while read line 。这样就不用再命令行输入bash Scription.sh < FILENAME
2、如果想把结果输出到FILENAME2中,则可以在命令行输入 bash Scription.sh <FILENAME1 >FILENAME2
3、同样也吧上面第19行改成: done >FILENAME2
4、还可以使用文件描述符来表示,[i]<>filename打开文件filename来读写,并且分配文件描述符i给这个文件。如果filename不存在,则他会被创建,然后 read -u fd ARG
2、提取子串,子串削除,子串替换
position开始提取子串,长度为$length(长度可以加在position后面也可不加)。
2.1、如果position开始的位置参数
2.2、string提取的时候是0-based indexing
2.3、position为负数时候,是倒数,但是需要加括号表示,
EG:
stringZ=abcABC123ABCabc
echo ${stringZ:0} #abcABC123ABCabc
echo ${stringZ:7:3} #23A
echo {stringZ:-default}一样了
echo ${*:2} #打印第二个以及后面的参数
expr substr position $length
EG: echo `expr substr $stringZ 1 2` #12
expr match "substring\)' == expr "substring\)' 都是提取子串
不同于返回子串长度 expr match "substring' == expr "substring' ,少了两个转义的小括号。加不加echo 效果也一样。
从结尾提取substring:
expr match "$string" '.*' == expr "$string" : '.*' [多了" .* " 在小括号前]
子串削除
substring
substring
${string%substring}从结尾开始截掉最短
${string%%substring}从结尾开始截掉最长
子串替换
replacement来替换第一个匹配的$substring
replacement来替换所有匹配的$substring
replacement匹配开头部分,则使用substring
replacement匹配结尾部分,则使用substring
图像转换:
1、关于Netpbm
Netpbm是一个很好用的,很强大的命令方式图像处理程序,(先将png转换成pnm格式,再将pnm转换成bmp.pnm是LINUX下的一种原始图像存储格式,类似于WINDOWS下的BMP).特别适合图像批量处理,尤其是在LINUX下与SHELL配合。
关于netpbm的相关programs可以在这个网站查找:http://www.linuxguruz.com/man-pages/?topic=pnm
jpg全名是JPEG [ Joint Photo graphic Experts Group ] 。JPEG图片以 24 位颜色存储单个位图。JPEG 是与平台无关的格式,支持最高级别的压缩,不过,这种压缩是有损耗的。渐近式 JPEG 文件支持交错。
所以对于将Linux中的jpg或者bmp文件转换成ppm.pnm,pbm都可以使用Netpbm库中的程序。
这里我们将jpg转化成pnm.使用的程序是jpegtopnm。
电子书里面给的是一个把Macpaint转化成pbm的shell脚本
1 #!/bin/bash
2 # cvt.sh:
3 # 将一个目录下的所有MacPaint格式的图片文件都转换为"pbm"各式的图片文件.
4
5 # 使用"netpbm"包中的"macptopbm"程序进行转换,
6 #+ 这个程序主要是由Brian Henderson(bryanh@giraffe-data.com)来维护的.
7 # Netpbm绝大多数Linux发行版的标准套件.
8
9 OPERATION=macptopbm
10 SUFFIX=pbm # 新的文件名后缀.
11
12 if [ -n "1 # 如果目录名作为参数传递给脚本...
15 else
16 directory=directory/* # 文件名匹配(filename globbing).
23 do
24 filename=OPERATION filename.file # 转换后删除原始文件.
30 echo "SUFFIX" # 从stdout输出转换后文件的文件名.
31 done
32
33 exit 0
在我的电脑上用命令 find / -name "*.jpg"
发现有很多jpg文件,但没有mac文件。同时我不想把源文件删除,而是把转化格式的文件放在另外一个文件夹中。我修改后的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | #!/bin/bash # 使用"netpbm"包中的"jpegtopnm"程序进行转换, #+ 这个程序主要是由Brian Henderson(bryanh@giraffe-data.com)来维护的. # Netpbm绝大多数Linux发行版的标准套件. OPERATION=jpegtopnm SUFFIX=pnm # 新的文件名后缀. if [ -n "$1" ] then directory=$1 # 如果目录名作为参数传递给脚本... else directory=$PWD # 否则使用当前的工作目录. fi if [ -n "$2" ] then redir=$PWD/$2 #如果接受目录作为参数传递给脚本 else mkdir Dirpnm redir=$PWD /Dirpnm fi # 假定目标目录中的所有文件都是MacPaint格式的图像文件, #+ 并且都是以".mac"作为文件名后缀. for file in $directory/* # 文件名匹配(filename globbing). do filename=${ file %.*g} # 去掉文件名的".jpg"后缀 #+ ('.*c' 将会匹配 #+ '.'和'c'之间任意字符串). recv=` basename $filename` exec 9>$redir/$recv.$SUFFIX #把这个目录绑定文件描述符 $OPERATION $ file >&9 #重定向到9,注意前面加& # 把结果重定向到新的文件中. # rm -f $file # 转换后删除原始文件.不删除了 echo "$filename.$SUFFIX" # 从stdout输出转换后文件的文件名. done exit 0 |
1、写出这个程序:首先要清楚 如何重定向。可以使用 exec [n] > filename 来重定向。如果不存在,则创建他。还有一种[n] <> filename 没有用出来
2、注意这里的filename是在directory下的filename是含有绝对路径的变量。如果我们需要在另外一个路径下转化,则只需要去basename然后在另外一个文件夹下进行重定向。
3、这个shell脚本的本意是为了学会如果对于字符串进行剪辑${string%substring}会截掉末尾最短的substring。(截掉开头最长的子串用##,开头最短用一个#)而这里的substring=".*g"就是jpg(貌似这个操作用basename也可做到)
3、使用awk来处理字符串
awk是功能完整的文本处理语言,使用类似于C的语法。他具有一套操作符和能力集,这里只讲在shell中最有用的一小部分。
Awk将传递进来的每行输入都分割成域. 默认情况下, 一个域指的就是使用空白分隔的一个连续字符串,不过我们可以修改属性来改变分隔符. Awk将会分析并操作每个分割域. 因为这种特性, 所以awk非常善于处理结构化的文本文件 -- 尤其是表 -- 将数据组织成统一的块, 比如说分成行和列.
强引用(单引号)和大括号用来包含shell脚本中的awk代码段
eg: echo one two | awk '{print $2}' ---> #two
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix