本文主要讲bash脚本中容易出错和很少用但是用起来有意想不到效果的部分。

循环:

正常的for循环:

for i in a b c 1 2 3; do
echo "$i"
done

数字序列循环:

for i in `seq `; do
echo "$i"
done

其中的 `seq ` 也可以换成 {..}

{开始..结尾}的这种形式可以表示连续的数列,可以从小到大也可以从大到小,但是可惜不像python的range()那样可以指定间隔量

C语言风格的for循环:

for (( i=; i<; i++ )); do
echo "$i"
done

for循环迭代文本

for循环会使用空格、换行符、制表符分割文本,依次迭代,如:

a="ab cd
ef" for i in $a; do
echo "$i"
done

输出结果:

ab
cd
ef

shell分割文本其实是以一个全局变量$IFS为依据的,默认情况下IFS=$'\n\t '(即换行符、制表符、空格),可以通过修改IFS的值来改变迭代文本的分割方式。

请注意上面的$a如果加引号括起来的话,会把它当成一个整体,不会切割迭代。

数学计算

双括号“(())”还可以用于数学计算:

(( a=+ ))
echo $a
#

在双括号中,变量并不需要用$符号来引用,英文单词天然是变量。

变量:

间接引用:

a=b
b=
echo ${!a}
#

效果等同于 eval echo \$$a

特殊字符转义

包含特殊字符的字符串:

echo "ab\ncd"

上列命令会输出字符ab+换行+cd,但是实际上字符串"ab\ncd"中并不包含“换行”这个字符,输出的换行只是echo命令解析的结果。

# a="ab\ncd"
# echo "length of var a is ${#a}" length of var a is

通过${#var}的形式可以得到一个字符串的长度,上面示例可以看出来,字符串"ab\ncd"的长度是6而不是预期的5。

那么能否将不可打印的字符赋值给变量呢?答案是肯定的:

# a=$'\x61\n\x62'
# echo "$a"
a
b

请注意一定用的是单引号“'”,用双引号括起来是不起转义作用的。

字符串操作

变量值字符截取:

a="abcdefg"
echo ${a:}
# cdefg
echo ${a::}
# cde

变量值字符删除:(#为从头部开始匹配,%为从尾部匹配,支持通配符“?*”)

a="abdcdefgh"
echo ${a#*d} # 删除字符串头部匹配“*d”的部分,通配符*代表匹配任意多个字符,一个#号代表通配符“*”保守匹配
# cdefgh
echo ${a##*d} # 两个#号表示贪婪匹配
# efgh
echo ${a%d*} # 同上,两个%时代表贪婪匹配
# abdc
a=b
b="abcdefg"
echo "${!a#abc}"
# defg

可以同时支持间接引用和字符删除

变量赋值安全

用于赋值前检查是否已经定义或赋值。

unset a
unset b
b="" # a没有定义,b定义了但是空值
echo ${a-}  # 如果没定义,则表达式采用默认值789
#
echo ${a:-} # 如果没定义或是空值,则表达式采用默认值789
#
echo ${b-} # 如果没定义,则表达式采用默认值789,b定义了
#
echo ${b:-} # 如果没定义或是空值,则表达式采用默认值789
#
echo $a # 原变量并没有被赋值
#
echo $b # 原变量并没有被赋值
#
b=
echo ${b-} # 如果变量已经被赋值,则不改变原有值
#
unset a
echo ${a=} # 如果a没定义,则表达式采用默认值,并给a赋值
#
echo $a
# # a已经被赋值了
a=""
echo ${a=}
#
echo ${a:=} # 加冒号:的作用和之前一样
#
echo $a
#

前面讲了用“-”和“=”的,还有一种用“+”的,用于当变量已经被赋值的情况下采用默认值,举一反三,不赘述了。

位置变量

$0是文件名,$#代表参数个数,$1,$2等等表示执行该脚本或函数后面跟的位置参数,$1代表第一个参数,依次类推,需要注意的是,第9个以后的参数应该这么表示:

${}

这表示第10个参数,必须用花括号括起来,否则就变成第1个变量后面加个字符“0”了。因为这个有的人以为第9个以后的位置变量就不可用了,是错的。

$@和$*都表示所有的变量,但是区别是前者将每个作为一个字符串,是多个字符串的结合,而后者将所有变量组合成一个字符串,用空格分隔。

这样不同会在for循环里面造成使用的区别,在for循环里面,如果加上引号 for i in "$@" 和 for i in "$*" 是不同的,前者还是会依次把参数代入循环,而后者会吧所有参数作为字符串一次性代入:

echo '
for i in "$@"; do
echo "$i"
done
for i in "$*"; do
echo "$i"
done
' > myscript.sh
chmod myscript.sh
./myscript.sh abc def

结果是:

abc

def
abc def

那么$@加引号和不加引号有区别么?

大部分情况下结果看起来是一样的,但会在某些情况下造成麻烦,因为for循环会用换行符“\n”和空格来拆分变量,所以如果调用脚本所带的参数中带有空格或者换行符,不加引号的时候会把这个参数拆开了依次代入,而加了引号就可以避免这种情况。

echo '
for i in "$@"; do
echo "$i"
done
for i in $@ ; do
echo "$i"
done
' > myscript.sh
chmod myscript.sh
./myscript.sh abc "123 def"

结果是:

abc
def
abc def

for循环使用数组

将数组的值依次代入循环,可以用${arr[@}和${arr[*]}这两种方法,区别和加引号的区别同上面位置参数的使用相同。

字符串比较

shell的字符串匹配通常是这样的:

[ "abc" = "abc" ]
echo $?
#

$? 这个变量代表上条命令的返回码。若字符串相同则返回0,否则返回1。除了全匹配外,通过双方括号“[[]]”还可以用正则表达式匹配

[[ "abc234def" =~ ^abc[-]{}[a-z]+$ ]]
echo $?
#

注意这里正则表达式不能用引号括起来,而且只支持基本的正则,不支持如“\b \S”之类的扩展。

另单方括号‘[ ]’和双方括号‘[[ ]]’的区别,单括号等同于bash内置test命令,双方括号不是命令,是bash关键字。

原文地址:http://www.cnblogs.com/foxgab/p/6901782.html

如果觉得本文对您有帮助,请扫描后面的二维码给予捐赠,您的支持是作者继续写出更好文章的动力!

linux shell编程-bash的奇技淫巧的更多相关文章

  1. linux —— shell 编程(文本处理)

    导读 本文为博文linux —— shell 编程(整体框架与基础笔记)的第4小点的拓展.(本文所有语句的测试均在 Ubuntu 16.04 LTS 上进行) 目录 基本文本处理 流编辑器sed aw ...

  2. linux —— shell 编程(编程语法)

    导读 本文为博文linux —— shell 编程(整体框架与基础笔记)的第4小点的拓展.(本文所有语句的测试均在 Ubuntu 16.04 LTS 上进行) 目录 再识变量 函数 条件语句 循环语句 ...

  3. linux shell编程总结

    linux shell编程总结 本周学习了unix/linux shell编程,参考的是<LINUX与UNIX Shell 编程指南>,David Tansley著:徐焱,张春萌等译,由机 ...

  4. Linux Shell编程参考大全

    本文记录Linux Shell编程中常用基本知识,方便快速入门以及查询使用. 本文主要分为以下几个部分: 一.Shell中的变量 任何编程语言中,有关变量的定义,作用范围,赋值等都是最最基础的知识. ...

  5. linux shell 编程参考

    #!/bin/bash my_fun() { echo "$#" } echo 'the number of parameter in "$@" is '$(m ...

  6. 一文学完Linux Shell编程,比书都好懂

    一. Shell 编程 1. 简介 Shell 是一个用 C 语言编写的程序,通过 Shell 用户可以访问操作系统内核服务. Shell 既是一种命令语言,又是一种程序设计语言. Shell scr ...

  7. 前端学习 linux —— shell 编程

    前端学习 linux - shell 编程 shell 原意是"外壳",与 kernel(内核)相对应,比喻内核外的一层,是用户和内核沟通的桥梁.shell 有很多种,国内通常使用 ...

  8. Linux Shell编程中的几个特殊符号命令 & 、&& 、 ||

    https://blog.csdn.net/hack8/article/details/39672145 Linux Shell编程中的几个特殊符号命令 & .&& . || ...

  9. Linux Shell编程与编辑器使用详解

    <Linux Shell编程与编辑器使用详解> 基本信息 作者: 刘丽霞 杨宇 出版社:电子工业出版社 ISBN:9787121207174 上架时间:2013-7-22 出版日期:201 ...

随机推荐

  1. JavaScript获取html元素的实际宽度和高度

    一.JavaScript获取html元素宽高 1.宽高都写在样式表里,就比如#div1{width:120px;}.这中情况通过#div1.style.width拿不到宽度,而通过#div1.offs ...

  2. bzoj2144 【国家集训队2011】跳跳棋

    Description 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子.我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过最少的跳动把他 ...

  3. 详解Session分布式共享(.NET CORE版)

    一.前言&回顾 在上篇文章Session分布式共享 = Session + Redis + Nginx中,好多同学留言问了我好多问题,其中印象深刻的有:nginx挂了怎么办?采用Redis的S ...

  4. hdu2717Catch That Cow 简单BFS

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2717 刚开始思路错了,用的DP,一直WA,后来才发现是搜索,还是简单的BFS,顿时.... 思路: B ...

  5. 用ajax写分页查询-----2017-05-17

    要写分页,首先你得清楚,一页你想显示多少条信息?如何计算总共显示的页数? 先说一下思路: (1)从数据库读取数据,以chenai表为例,读取所有留言信息.并能够实现输入发送者,可以查询该发送者的留言总 ...

  6. spring boot无法启动,或者正常启动之后无法访问报404的解决办法

    以前用spring boot都是用idea的自动创建,或者是用的Jhipster创建的,就没有深究怎么去搭建.但是今天晚上心血来潮,想自己搭一个demo来整合一些技术,于是就花一点时间来手动搭.因为今 ...

  7. Hive的分区操作~~~~~~

    一.Hive分区(一).分区概念:为什么要创建分区:单个表数据量越来越大的时候,在Hive Select查询中一般会扫描整个表内容,会消耗很多时间做没必要的工作.有时候只需要扫描表中关心的一部分数据, ...

  8. 【JAVAWEB学习笔记】23_Listener和邮箱服务器

    监听器Listener 学习目标 案例-使用监听器完成定时生日祝福 一.监听器Listener javaEE包括13门规范 在课程中主要学习 servlet技术 和 jsp技术 其中 servlet规 ...

  9. swift学习 - collectionView

    swift CollectionView学习 效果图: 源码: ContModel.swift import UIKit class ContModel: NSObject { var title:S ...

  10. Java基础知识二次学习--第七章 容器

    第七章 容器   时间:2017年4月27日15:08:30 章节:07章01节~07章04节 视频长度:20:21 +12:38 +3:55 +2:57 内容:容器API 心得: Java API ...