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,后面的参数就是为空了

技术分享图片技术分享图片


[email protected]

由于跟以上演示只是相差了一点,将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 编程基础的主要内容,如果未能解决你的问题,请参考以下文章

shell编程基础

Shell脚本编程基础

第九章shell脚本编程基础

SHELL脚本编程基础

第17篇 shell编程基础

编程语言和shell编程基础