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