Bash编程(6) String操作
1. 拼接
1) 简单的字符串拼接如:PATH=$PATH:$HOME/bin。如果拼接的字符串包含空格或特殊字符,需要使用双引号括起,如:
var=$HOME/bin # 注释并不是赋值的一部分
var="$HOME/bin # but this is" # bash .1后,可以使用+=拼接(+=也可用于数组相加)
var=abc $ var=abc
$ var+=xyz
$ echo "$var"
abcxyz
注意:+=的性能较直接拼接的效率高,测试如下:
$ var=; time for i in {..}; do var=${var}foo; done; real 0m1.251s
user 0m1.144s
sys 0m0.104s
$ var=; time for i in {..}; do var+=foo; done; real 0m0.156s
user 0m0.156s
sys 0m0.000s
2) 重复字符到指定长度
_repeat(){
#@ 功能:重复字符串到指定长度
_REPEAT=
while (( ${#_REPEAT} < $))
do
_REPEAT+=$
done
} $ _repeat %
$ printf "%s\n" "$_REPEAT"
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
通过拼接在每个循环中拼接多个实例来提高函数速度:
_repeat(){
#@ 功能:重复字符串到指定长度
_REPEAT=$
while (( ${#_REPEAT} < $))
do
_REPEAT=$_REPEAT$_REPEAT$_REPEAT
done
_REPEAT=${_REPEAT:-:$} ## 裁剪指定长度字符串
} repeat(){
_repeat "$@"
printf "%s\n" "$_REPEAT"
} alert(){ #@ 功能: 打印包含边界及鸣响的警告信息
_repeat "${2:-#}" $(( ${#} + ))
printf '\a%s\n' "$_REPEAT" ## \a = BEL
printf '%2.2s %s %2.2s\n' "$_REPEAT" "$1" "$_REPEAT"
printf '%s\n' "$_REPEAT" } $ alert "Do you really want to detele all your files?" #################################################################################
## Do you really want to detele all your files? ##
#################################################################################
2. 字符处理
没有直接的参数扩展来提供字符串的首字符或尾字符,可借助通配符问号?,以及字符串截取来抽取首字符或尾字符。
$ var=strip
$ allbutfirst=${var#?} # 去除首字符
$ allbutlast=${var%?} # 去除尾字符
$ printf "%8s %8s\n" "$allbutfirst" "$allbutlast"
trip stri
$ first=${var%"$allbutfirst"}
$ last=${var#"$allbutlast"}
$ printf "%8s %8s\n" "$first" "$last"
s p ## 小测试
$ while [ -n "$var" ]; do temp=${var#?}; char=${var%"$temp"}; printf "%s\n" "$char"; var=$temp; done ## 将字符串的每个字母按行打印
s
t
r
i
p
$ while [ -n "$var" ]; do temp=${var%?}; char=${var#"$temp"}; printf "%s\n" "$char"; var=$temp; done ## 将字符串的每个字母反向打印
p
i
r
t
s
也可以通过"%c"获取字符串首字符
$ printf -v first "%c" "$var" # 将原本输出到标注输出的信息赋值给first
$ echo $first
s
3. 大小写转换
Bourne shell中,字符转换可以通过tr命令完成,tr作用:将第一个参数中的字符转换成对应的第二个参数中的字符
$ echo abcdefgh | tr ceh CEH ## c=>C,e=>E,h=>H
abCdEfgH
$ echo abcdefgh | tr ceh HEC ## c=>H,e=>E,h->C
abHdEfgC
$ echo touchdown | tr 'a-z' 'A-Z' ## 将小写转换为大写
TOUCHDOWN
POSIX shell中,可以通过参数扩展来完成。
to_upper(){
case $ in
a*) _UPR=A;; b*) _UPR=B;; c*) _UPR=C;; d*) _UPR=D;;
e*) _UPR=E;; f*) _UPR=F;; g*) _UPR=G;; h*) _UPR=H;;
i*) _UPR=I;; j*) _UPR=J;; k*) _UPR=K;; l*) _UPR=L;;
m*) _UPR=M;; n*) _UPR=N;; o*) _UPR=O;; p*) _UPR=P;;
q*) _UPR=Q;; r*) _UPR=R;; s*) _UPR=S;; t*) _UPR=T;;
u*) _UPR=U;; v*) _UPR=V;; w*) _UPR=W;; x*) _UPR=X;;
y*) _UPR=Y;; z*) _UPR=X;; *) _UPR=${%${#?}};;
esac
} $word=function
$to_upper "$word"
$printf "%c%s\n" "$_UPR" "${word#?}"
Function ## 将所有字符转换为大写
_upword(){
local word=$
while [ -n "$word" ] ## 循环直到$word为空
do
to_upper "$word"
_UPWORD=$_UPWORD$_UPR
word=${word#?} ## 移除$word中的首字母
done
} upword(){
_upword "$@"
printf "%s\n" "$_UPWORD"
}
4. 比较内容且不需考虑大小写
当输入为单个字母,例如请求Y或N,可以使用逻辑运算符或(|)或者方括号([])对大小写进行选择。
read ok
case $ok in
y|Y) echo "Great!" ;;
n|N) echo Good-bye; exit ;;
*) echo Invalid entry ;;
esac read ok
case $ok in
[yY]) echo "Great!" ;;
[nN]) echo Good-bye; exit ;;
*) echo Invalid entry ;;
esac
当输入较长时,以上方法需要将所有的可能组合进行展示,这样的方法较为繁琐。
## 针对于"|",需要列出所有组合
jan | jaN | jAn | jAN | Jan | JAn | JAN) echo "Great!" ;; ## 对于"[]",脚本不宜阅读
read monthname
case $monthname in
[Jj][Aa][Nn]*) month= ;;
[Ff][Ee][Bb]*) month= ;;
## 输入剩余的月份
[Dd][Ee][Cc]*) month= ;;
[-][-] month=$monthname ;; 考虑输入数字的情况
*) echo "Invalid month: $monthname" >& ;;
esac
较好的方法是将输入统一转换为大写或小写再进行比较:
_upword "$monthname"
case _UPWORD in
JAN*) month= ;;
FEB*) month= ;;
## 输入剩余的月份
DEC*) month= ;;
[-]|[-]) month=$monthname
*) echo "Invalid month: $monthname" >& ;;
esac
bash 4.*中字符转换为大写,也可采用${monthname^^}执行
5. 检查变量名的有效性
检查变量名是否满足仅包含字母、数字和下划线,且只能以字母和下划线开头。
validname(){
case $ in
[!a-zA-Z_]* | *[!a-zA-Z0-9_]*) return ;;
esac
} for name in name1 2var first.name first_name last-name
do
validname "$name" && echo " valid: $name" || echo "invalid: $name"
done valid: name1
invalid: 2var
invalid: first.name
valid: first_name
invalid: last-name
6. 字符串插入
_insert_string(){ #@功能: 在字符串的指定位置插入字符串
local insert_string_dflt= ## 默认的插入位置
local string=$ ## 被插入的字符串
local i_string=$ ## 待插入字符串
local i_pos=${:-${insert_string_dflt:-}} ## 插入位置
local left right
left=${string::$(( $i_pos - ))}
right=${string:$(( $i_pos - ))}
_insert_string=$left$i_string$right
} insert_string(){
_insert_string "$@" && printf "%s\n" "$_insert_string"
} $ insert_string poplar u
popular
$ insert_string show ad
shadow
$ insert_string tail ops ## 使用默认位置
topsail
7. 覆盖
在一个字符串上覆盖另一个字符串。
_overlay(){
local string=$
local sub=$
local start=$
local left right
left=${string::start-}
right=${string:start+${#sub}-}
_OVERLAY=$left$sub$right
} overlay(){
_overlay "$@" && printf "%s\n" "$_OVERLAY"
} $ {
> overlay pony b
> overlay pony u
> overlay pony s
> overlay pony d
> }
bony
puny
posy
pond
8. 裁剪不想要的字符
字符串首尾的空格可以通过循环和条件判断完成。
var=" John "
while : ## 无限循环
do
case $var in
' '*) var=${var#?} ;; ## 如果字符串以空格开始,则移除
*' ') var=${var%?} ;; ## 如果字符串以空格结尾,则移除
*) break; ## 当字符串的头部或尾部均无空格,则退出循环
esac
done
更有效的方法是找到首尾最长待删除的空格,然后从原始字符串中删除。
var=" John "
printf "%s|%s\n" "$var" "${#var}"
rightspaces=${var##*[! ]} ## 删除一切直到最后一个非空值
printf "%s|%s\n" "$rightspaces" ${#rightspaces} ## rightspaces为4个空格
var=${var%"$rightspaces"} ## var目前为"John "
printf "%s|%s\n" "$var" "${#var}"
leftspaces=${var%%[! ]*} ## 从第一个非空值删除直到结尾
printf "%s|%s\n" ${leftspaces} ${#leftspaces}
var=${var#"$leftspaces"}
printf "%s|%s\n" "$var" "${#var}"
进一步封装的方法如下:如果存在第二个参数,则从字符串中删除该参数对应的字符,如果为空,则默认删除空格。
_trim(){ #@ 从$1中删除空格(或$2中的字符)
local trim_string
_TRIM=$
printf "%s|%s\n" "$_TRIM" ${#_TRIM}
trim_string=${_TRIM##*[!${:- }]}
printf "%s|%s\n" "$trim_string" ${#trim_string}
_TRIM=${_TRIM%"$trim_string"}
printf "%s|%s\n" "$_TRIM" ${#_TRIM}
trim_string=${_TRIM%%[!${:- }]*}
printf "%s|%s\n" "$trim_string" ${#trim_string}
_TRIM=${_TRIM#"$trim_string"}
printf "%s|%s\n" "$_TRIM" ${#_TRIM}
} trim(){
_trim "$@" && printf "%s\n" "$_TRIM"
} $ trim " S p a c e d o u t "
S p a c e d o u t
$ trim "0002367.45000"
2367.45
9. 索引
定位一个字符串在另一个字符串中的索引位置。
_index(){ #@ $2在$1中的位置保存在$_INDEX
local idx
case $ in
"") _INDEX=; return ;;
*"$2"*) idx=${%%"$2"*} ## 提取匹配位置的起始
_INDEX=$(( ${#idx} + )) ;;
*) _INDEX=; return ;;
esac
} index(){
_index "$@" && printf "%d\n" "$_INDEX"
}
例:基于月份的前3个字母,打印出对应的数值
_month2num(){
local month=JAN.FEB.MAR.APR.MAY.JUN.JUL.AUG.SEP.OCT.NOV.DEC
_upword "${1:0:3}" ## 提取$1中的前3个字母,并转换为大写
_index "$month" "$_UPWORD" || return
_MONTH2NUM=$(( $_INDEX / + ))
} month2num(){
_month2num "$@" && printf "%s\n" "$_MONTH2NUM"
}
Bash编程(6) String操作的更多相关文章
- bash编程基础
bash变量 变量命名: 1.不能使用程序中的关键字(保留字) 2.只能使用数字.字母和下划线,且不能以数字开头 3.要见名知义 变量类型: 数值型:精确数值(整数),近似数值(浮点型) 字符型:ch ...
- 怎样用 Bash 编程:逻辑操作符和 shell 扩展
学习逻辑操作符和 shell 扩展,本文是三篇 Bash 编程系列的第二篇. Bash 是一种强大的编程语言,完美契合命令行和 shell 脚本.本系列(三篇文章,基于我的 三集 Linux 自学课程 ...
- SHell string操作 转
本文也即<Learning the bash Shell>3rd Edition的第四章Basic Shell Programming之读书笔记之二,但我们将不限于此. String操作 ...
- C# winform编程中多线程操作控件方法
private void Form1_Load(object sender, EventArgs e) { Thread newthread = new Thread(new ThreadStart( ...
- Scala学习教程笔记三之函数式编程、集合操作、模式匹配、类型参数、隐式转换、Actor、
1:Scala和Java的对比: 1.1:Scala中的函数是Java中完全没有的概念.因为Java是完全面向对象的编程语言,没有任何面向过程编程语言的特性,因此Java中的一等公民是类和对象,而且只 ...
- bash编程之循环控制:
bash编程之循环控制: for varName in LIST; do 循环体 done while CONDITION; do 循环体 done until CONDITION; do 循 ...
- [shell] Bash编程总结
由于工作需要,之前的几个月写了一些Bash脚本,主要完成自动测试.打包.安装包等.虽然相比C++编程,要简单.傻瓜,但其在类Unix系统中可以大大提高工作的效率.所以在此对脚本编程过程中一些注意事项进 ...
- bash编程的信号捕获:
bash编程的信号捕获: kill -l KILL无法捕捉: trap 'COMMAND' SIGNAL, 信号捕捉用于:在中途中止时做一些清理操作. 一. trap捕捉到信号之后,可以 ...
- shell编程系列25--shell操作数据库实战之备份MySQL数据,并通过FTP将其传输到远端主机
shell编程系列25--shell操作数据库实战之备份MySQL数据,并通过FTP将其传输到远端主机 备份mysql中的库或者表 mysqldump 常用参数详解: -u 用户名 -p 密码 -h ...
随机推荐
- Verilog MIPS32 CPU(八)-- 控制器
Verilog MIPS32 CPU(一)-- PC寄存器 Verilog MIPS32 CPU(二)-- Regfiles Verilog MIPS32 CPU(三)-- ALU Verilog M ...
- TDE--相关Demo
SQL Server 2008引入透明数据加密(Transparent Data Encryption),它允许你完全无需修改应用程序代码而对整个数据库加密.当一个用户数据库可用且已启用TDE时,在写 ...
- hadoop2.2.0编译、安装和测试
搭建环境:单机64位CentOS6.5 .jdk1.6.0_45.Hadoop2.2.0 1.准备编译环境 从http://www.apache.org/dyn/closer.cgi/hadoop/c ...
- python的reflect反射方法
核心内容专自:http://www.liujiangblog.com/course/python/48 在自动化测试的时候,需要从excel中读取关键字,此关键字对应一个方法,如何使用该关键字去调用真 ...
- 造个轮子之基于 Netty 实现自己的 RPC 框架
原文地址: haifeiWu和他朋友们的博客 博客地址:www.hchstudio.cn 欢迎转载,转载请注明作者及出处,谢谢! 服务端开发都会或多或少的涉及到 RPC 的使用,当然如果止步于会用,对 ...
- 转载:RabbitMQ常用命令
RabbitMQ常用命令 RabbitMQ常用命令 rabbitmqctl命令http://www.rabbitmq.com/man/rabbitmqctl.1.man.html# 1). 服务器启动 ...
- 南昌网络赛J. Distance on the tree 树链剖分+主席树
Distance on the tree 题目链接 https://nanti.jisuanke.com/t/38229 Describe DSM(Data Structure Master) onc ...
- 集成 jpush-react-native 常见问题汇总 (iOS 篇)
给 iOS 应用添加推送功能是一件比较麻烦的事情,本篇文章收集了集成 jpush-react-native 的常见问题,目的是为了帮助用户更好地排查问题 1. 收不到推送 确保是在真机上测试,而不是在 ...
- java学习笔记_多态
多态:父类的变量可以引用子类的对象 引用: Student s1 = stu; s1.setScore(200); 1.一个对象可以有多个引用,可以有多个变量操作同一个对象 2.当一个对象没有任何 ...
- luogu P1080国王游戏
贪心加高精 传送门:QWQ 先考虑两个人 a0 b0 p1 a1 b1 p2 a2 b2 那么满足:\(\huge ans1=\max(\frac{a0}{b1} , \frac{a0a1}{b2}) ...