Shell 编程基础
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Shell 编程基础相关的知识,希望对你有一定的参考价值。
shift 参数向左移一位
shift + 数字,参数一次向左移N位
编程的时候可以用来判断后面还有几个参数
当shift后值为空的时候,返回错误
使用read来把输入值分配给一个或多个shell变量
read 从标准输入中读取值,给每个单词分配一个变量
所有剩余单词都被分配给最后一个变量
bash如何展开命令行
按以下优先级顺序
把命令行分成单个命令词
展开别名
展开大括号的声明({})
展开波浪符声明(~)
命令替换$() 和 ``
再次把命令行分成命令词
展开文件通配(*、 ?、 [abc]等等)
准备I/0重导向(<、 >)
运行命令
转义
反斜线(\)会使随后的字符按原意解释
$ echo Your cost: \$5.00
Your cost: $5.00
加引号来防止扩展
? 单引号(’)防止所有扩展
? 双引号(”)也防止所有扩展,但是以下情况例外:
$(美元符号) - 变量扩展
`(反引号) - 命令替换
\(反斜线) - 禁止单个字符扩展
!(叹号) - 历史命令替换
环境配置相关
bash的配置文件
按生效范围划分,存在两类:
全局配置:
/etc/profile
/etc/profile.d/*.sh
/etc/bashrc
个人配置:
~/.bash_profile
~/.bashrc
配置文件的生效顺序与范围
交互式登录:
(1)直接通过终端输入账号密码登录
(2)使用“ su - UserName” 切换的用户
执行顺序:/etc/profile --> /etc/profile.d/*.sh -->~/.bash_profile --> ~/.bashrc --> /etc/bashrc
? 非交互式登录:
(1)su UserName
(2)图形界面下打开的终端
(3)执行脚本
(4)任何其它的bash实例
执行顺序: ~/.bashrc --> /etc/bashrc -->/etc/profile.d/*.sh
Profile类
? 按功能划分,存在两类:
profile类和bashrc类
? profile类:为交互式登录的shell提供配置
全局:/etc/profile, /etc/profile.d/*.sh
个人:~/.bash_profile
功用:
(1) 用于定义环境变量
(2) 运行命令或脚本
bashrc类
? bashrc类:为非交互式和交互式登录的shell提供配置
全局:/etc/bashrc
个人:~/.bashrc
功用:
(1) 定义命令别名和函数
(2) 定义本地变量
编辑配置文件生效
? 修改profile和bashrc文件后需生效
两种方法:
1重新启动shell进程
2 . 或source
例:
. ~/.bashrc
bash 退出任务
? 保存在~/.bash_logout文件中(用户)
? 在退出登录shell时运行
? 用于
创建自动备份
清除临时文件
$-变量
? h:hashall,打开这个选项后,Shell 会将命令所在的路径hash下来,避免每次都要查询。通过set +h将h选项关闭
? i:interactive-comments,包含这个选项说明当前的 shell是一个交互式的 shell。所谓的交互式shell,在脚本中,i选项是关闭的。
? m:monitor,打开监控模式,就可以通过Job control来控制
进程的停止、继续,后台或者前台执行等。
? B:braceexpand,大括号扩展
? H:history,H选项打开,可以展开历史列表中的命令,可以
通过!感叹号来完成,例如“!!”返回上最近的一个历史命令,
“!n”返回第 n 个历史命令
$* 与[email protected]的区别
$*
以下是a.sh的脚本代码:
以下是b.sh的脚本代码
看到了吧,$*把所有参数当成了一个整体,所以b.sh的第一个参数就是a b c,后面的参数就是为空了
由于跟以上演示只是相差了一点,将b.sh调用变成[email protected]
看到了吧,[email protected]把所有参数当成了独立的个体,所以b.sh的各个参数就是a.sh一样了。
shift作用演示
以下为脚本内容:
echo "这个脚本的名字是:`basename $0`"
echo "第一个参数是:$1"
echo "第二个参数是:$2"
echo "第三个参数是:$3"
echo "演示下shift参数调整功能,这里只是一次一个,shift后面可以接具体数字的"
shift
echo "第一个参数是原来的\$2参数:$1"
echo "第二个参数是原来的\$3参数:$2"
echo "第三个参数是原来的\$3之后的参数,因为是没有,应该是空的:$3"
逻辑运算
true =1 false =0
与运算
1与1 为1
只要有0就为0
或运算
只要有1就为1
0与0 为0
非
! 0 为1
! 1 为 0
shell编程中的短路运算
短路与
第一个为0,结果必定为0
第一个为1,第二个必须要参与运算
比如:
命令1 && 命令2
当命令1返回值为0,也就是真的时候,命令2必须参与运算
当命令1返回值为1,也就是假的时候,命令2不会参与运算
短路或
第一个为1,结果必定为1
第一个为0,第二个必须要参与运算
比如:
命令1 || 命令2
当命令1返回值为1,也就是假的时候,命令2必须参与运算
当命令1返回值为0,也就是真的时候,命令2不会参与运算
异或:^
异或的两个值,相同为假,不同为真
比如:
命令1 ^ 命令2
当命令1和命令2返回值都相同的时候,得出的就是假
当命令1和命令2返回值不相同的时候,得出的就是真
看以下例子,操作符位置不一样,结果就不一样了,为什么第一条会同时显示2条信息呢?
第一条指令集返回状态是这么解读的:第一条命令查找不到用户,返回值为非0,假,因此将会执行||这后的命令并且输出成功,返回值为0,真,因此就会执行&&之后的命令,并且成功输出并且返回值为0.
所以会显示出2条信息。
第二条指令集返回状态是这么解读的:第一条命令查找不到用户,返回值为非0,假,与后面是与的关系,后面不管是真假,最终的结果都是假了,所以会执行||之后的命令并且输出成功,返回值为0
下图我们故意把echo输入错误,变成echoa,这样,这一条指令就会返回为非0,假
指令集返回状态是这么解读的:第一条命令查找到用户,返回值为0,真,因此会执行后面的指令,可是后面的指令是错误的命令,会返回非0,假,与后面的指令是或的关系,它必须执行,输出成功,返回值为0
特殊运算结果产生的坑
expr 和let命令计算的时候,要注意
expr 计算的结果是null或0的时候,$?返回的值为1
let计算的时候,最后一个参数为0的时候,返回值为1
中括号可以用来判断变量是否为空,请仔细观察以下变化。中括号内的变量记得用双引号
也可以使用一个字符+变量来组合判断变量是否会空
双中括号里一些使用规范
[[ "$var" == "abc" ]] 判断2边字符串是否相等时,使用==
[[ "$var" =~ \.sh$ ]] 当使用=~扩展正则表达式时,表达式不需要带引号
如果是在比较字符串的时候,==后面加引号表过的是字符串,不加引号表示的是通配符,因此,这种情况比较容易搞蒙自己。那么建议是这样的:只有涉及到需要使用正则表达式的时候才使用双括号。
BUG
以下是bash的一个BUG了哦,只要在正则表达式里面出现了反斜线,就会导致匹配失败,因此,解决方案就是把正则表达式内容用变量代替。
以下是2个不同的案例对比
来个简单点的正则吧
测试条件时
-v 变量名 检查变量是否已经设置
Centos 6 是不支持 -v 的
num="";[ -v num ] && echo "设置" || echo "未设置"
Centos 7
num="";[ -v num ] && echo "设置" || echo "未设置"
分组
linux中shell的小括号、大括号的用法区别
小括号()
①命令组。括号中的命令新开一个子shell程序,括号中的变量为本地变量 ,不能够在脚本其他部分使用。括号中多个命令之间用分号隔开。
②命令替换。命令替换$(cmd)等同于`cmd`(这不是单引号,`是ESC下面的那个键) ,shell执行过程中发现了$(cmd)结构,便将$(cmd)中的cmd执行一次,得到其输出,再将此输出放到原来命令。例如:
这是一个实例,如果没有加上小括号的时候,cd /app/dir/ 后,再执行pwd可以看到确实是进入了目录,但是当括号内的pwd命令执行完之后,命令提示符显示的就是/app,也就是cd命令前的目录。因为cd命令是作用在子进程了。在实际中的应用场景的话,就是临时开启一个子进程执行一些操作而不影响当前环境
③用于初始化数组。如:arr=(m n)
大括号 { }
①拓展。对大括号中的文件名做扩展。在大括号中,不允许有空白,除非这个空白被引用或转义。拓展分为普通以逗号(,)进行拓展,如echo {a,b}.txt将间隔的各项内容均列出;以两个点(..)进行拓展,如echo {1..5}.txt自动补全1到5中间内容。
# echo {a,b}.txt
a.txt b.txt
# echo {1..5}.txt
1.txt 2.txt 3.txt 4.txt 5.txt
②内部组 。与小括号中的命令不同,大括号内的命令在当前shell运行,不会重新开子shell。括号内的命令间用分号隔开,最后一个命令后必须跟分号。{}的第一个命令和左括号之间必须要有一个空格。
在Shell中的小括号,大括号结构和有括号的变量,命令的用法如下:
1.${var}
2.$(cmd)
3.()和{}
4.${var:-string},${var:+string},${var:=string},${var:?string}
5.$((exp))
6.$(var%pattern),$(var%%pattern),$(var#pattern),$(var##pattern)
现在来一一详细介绍:
1)Shell中变量的原形
这个最常见的变量形式就是$var,打印var用命令
echo $var
可是这里有个问题:当你要显示变量值加随意的字符(如$varAA)时,就会出错。系统会认为整个varAA是一个变量,这时就可以用一个大括号来限定变量名称的范围,如${var}AA,这样就好了。
此时正是使用 {大括号} 的时候了
2)命令替换$(cmd)
命令替换$(cmd)和符号`cmd`(注意这不是单引号,在美式键盘上,`是ESC下面的那个键)有相同之处.以echo$(ls)来说明整个替换过程:shell扫描一遍命令行,发现了$(cmd)结构,便将$(cmd)中的cmd执行一次,得到其标准输出,再将此输出放到原来命令echo $(ls)中的$(ls)位置,即替换了$(ls),再执行echo命令。如下:
3)一串的命令执行()和{}
()和{}都是对一串的命令进行执行,但有所区别:
A, ()只是对一串命令重新开一个子shell进行执行
B, {}对一串命令在当前shell执行
C, ()和{}都是把一串的命令放在括号里面,并且命令之间用;号隔开
D, ()最后一个命令可以不用分号
E, {}最后一个命令要用分号
F, {}的第一个命令和左括号之间必须要有一个空格
G, ()里的各命令不必和括号有空格
H, ()和{}中括号里面的某个命令的重定向只影响该命令,但括号外的重定向则影响到括号里的所有 命令
以上是关于Shell 编程基础的主要内容,如果未能解决你的问题,请参考以下文章