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"'或'expr + "$x" : '.*/(.)''可以正常被测试,即使"$x"的值可能是'/'或'index'关键字。这个操作符是一个GUN扩展。

更多的详细内容可以看大佬博文

字符串长度:法1:echo `expr length $Stringname`

      法2:echo ${#Stringname}

      法3:echo `expr "$Stringname" : '.*'`  ==  expr "$Stringname" : '.*'

抄个例子,在一个文本文件的段落之间插入空行

 #!/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、提取子串,子串削除,子串替换

${string:position} :在位置$position开始提取子串,长度为$length(长度可以加在position后面也可不加)。

2.1、如果$string 是“*”或“@”,那么将会提取从$position开始的位置参数

2.2、string提取的时候是0-based indexing

2.3、position为负数时候,是倒数,但是需要加括号表示,

EG:

stringZ=abcABC123ABCabc

echo ${stringZ:0}  #abcABC123ABCabc

echo ${stringZ:7:3}  #23A

echo ${stringZ:(-4)}  #Cabc。倒数第4个开始? 注意加括号转义,如果不加 可能为${stringZ:-default}一样了

echo ${*:2}  #打印第二个以及后面的参数

expr substr $string $position $length

EG:  echo `expr substr $stringZ 1 2`  #12

expr match "$string" '($substring)'  == expr "$string" : '($substring)'  都是提取子串

不同于返回子串长度  expr match "$string" '$substring'  == expr "$string" : '$substring'  ,少了两个转义的小括号。加不加echo 效果也一样。

从结尾提取substring:

expr match "$string" '.*($substring)'  == expr "$string" : '.*($substring)'    [多了"  .*   " 在小括号前]

子串削除

${string#substring}从string 的开始位置截掉最短匹配的$substring

${string##substring}从string的开头位置开始截掉最长的$substring

${string%substring}从结尾开始截掉最短

${string%%substring}从结尾开始截掉最长

子串替换

${string/substring/replacement}使用$replacement来替换第一个匹配的$substring

${string//substring/replaement}使用$replacement来替换所有匹配的$substring

${string/#substring/replaement}如果$replacement匹配开头部分,则使用$replacement来替换匹配的$substring

${string/%substring/replaement}如果$replacement匹配结尾部分,则使用$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" ]
13 then
14 directory=$1 # 如果目录名作为参数传递给脚本...
15 else
16 directory=$PWD # 否则使用当前的工作目录.
17 fi
18
19 # 假定目标目录中的所有文件都是MacPaint格式的图像文件,
20 #+ 并且都是以".mac"作为文件名后缀.
21
22 for file in $directory/* # 文件名匹配(filename globbing).
23 do
24 filename=${file%.*c} # 去掉文件名的".mac"后缀
25 #+ ('.*c' 将会匹配
26 #+ '.'和'c'之间任意字符串).
27 $OPERATION $file > "$filename.$SUFFIX"
28 # 把结果重定向到新的文件中.
29 rm -f $file # 转换后删除原始文件.
30 echo "$filename.$SUFFIX" # 从stdout输出转换后文件的文件名.
31 done
32
33 exit 0

在我的电脑上用命令 find / -name "*.jpg"

发现有很多jpg文件,但没有mac文件。同时我不想把源文件删除,而是把转化格式的文件放在另外一个文件夹中。我修改后的代码如下:

 #!/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

原文地址:https://www.cnblogs.com/SsoZhNO-1/p/9315871.html