第九章shell脚本编程基础

Posted sunan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第九章shell脚本编程基础相关的知识,希望对你有一定的参考价值。

第九章、shell脚本编程基础

本章内容

  • 编程基础
  • 脚本基本格式
  • 变量
  • 运算
  • 条件测试
  • 配置用户环境

编程基础

  • 程序:指令+数据
  • 程序编程风格:

过程式:以指令为中心,数据服务于指令

对象式:以数据为中心,指令服务于数据

  • shell程序:提供了编程能力,解释执行

程序的执行方式

  • 计算机:运行二进制指令
  • 编程语言:

低级:汇编

高级:

编译:高级语言-->编译器-->目标代码

        java,C#

解释:高级语言-->解释器-->机器代码

        shell, perl, python

(系统后台有个解释器,直接将语言转化为机器码,放到内存中直接运行)

编程基本概念

  • 编程逻辑处理方式:

顺序执行

循环执行

选择执行

  • shell编程:过程式、解释执行

编程语言的基本结构:

各种系统命令的组合

数据存储:变量、数组

表达式: a + b

语句:if

shell脚本基础

  • shell脚本:

包含一些命令或声明,并符合一定格式的文本文件

  • 格式要求:首行shebang机制

#!/bin/bash(告诉系统是哪种shell语法)

#!/usr/bin/python

#!/usr/bin/perl

  • shell脚本的用途有:

自动化常用命令(三次命令以上,推荐使用脚本)

执行系统管理和故障排除

创建简单的应用程序

处理文本或文件

创建shell脚本

  • 第一步:使用文本编辑器来创建文本文件

第一行必须包括shell声明序列:#!

#!/bin/bash

添加注释

注释以#开头

  • 第二步:运行脚本

给予执行权限,在命令行上指定脚本的绝对或相对路径

直接运行解释器,将脚本作为解释器程序的参数运行

脚本规范

  • 脚本代码开头约定

1、第一行一般为调用使用的语言

2、程序名,避免更改文件名为无法找到正确的文件

3、版本号

4、更改后的时间

5、作者相关信息

6、该程序的作用,及注意事项

7、最后是各版本的更新简要说明

脚本的基本结构

  • 脚本的基本结构

#!SHEBANG

CONFIGURATION_VARIABLES

FUNCTION_DEFINITIONS

MAIN_CODE

  • shell脚本示例

#!/bin/bash

# ------------------------------------------

# Filename: hello.sh

# Revision: 1.1

# Date: 2017/11/22

# Author: sunan

# Email: [email protected]

# Website: www.sunanblog.com

# Description: This is the first script

# ------------------------------------------

# Copyright: 2017 sunan

# License: GPL

echo “hello shell”

脚本调试

  • 检测脚本中的语法错误

bash -n /path/to/some_script(检查语法错误,不检查命令错误)

  • 调试执行

bash -x /path/to/some_script(检查语法和命令错误)

变量

  • 变量:命名的内存空间

数据存储方式:

字符:

数值:整型,浮点型

  • 变量:变量类型

作用:

1、数据存储格式

2、参与的运算

3、表示的数据范围

类型:

字符

数值:整型、浮点型

  • 强类型:变量不经过强制转换,它永远是这个数据类型,不允许隐式的类型转换。一般定义变量时必须指定类型、参与运算必须符合类型要求;调用未声明变量会产生错误

如 java,c#

  • 弱类型:语言的运行时会隐式做数据类型转换。无须指定类型,默认均为字符型;参与运算会自动进行隐式类型转换;变量无须事先定义可直接调用

如:bash 不支持浮点数,php

  • 变量命名法则:

1、不能使程序中的保留字:例如if, for

2、只能使用数字、字母及下划线,且不能以数字开头

3、见名知义

4、统一命名规则:小驼峰命名法和大驼峰命名法

例如:firstFunctionName( )(小驼峰命名法)

      FirstClassName( )   (大驼峰命名法)

bash中变量的种类

  • 根据变量的生效范围等标准划分下面变量类型:

局部变量:生效范围为当前shell进程;对当前shell之外的其它shell进程,包括当前shell的子shell进程均无效(如何查看当前的shell属于哪个bash进程,见附录1)

环境(全局)变量:生效范围为当前shell进程及其子进程

本地变量:生效范围为当前shell进程中某代码片断,通常指函数

位置变量:$1, $2, ...来表示,用于让脚本在脚本代码中调用通过命令行传递给它的参数

特殊变量:$?, $0, $*, [email protected], $#,$$

局部变量

  • 变量赋值:name=‘value’(=两边不要加空格)

  将变量赋两遍值,不是将原来空间的值覆盖,而是新开辟一个空间进行赋值,

  变量指向新的空间值,而原来的空间闲置并被别的赋值覆盖。(2.66)

  • 可以使用引用value:

(1) 可以是直接字串; name=“root"

(2) 变量引用:name="$USER"

(3) 命令引用:name=`COMMAND` name=$(COMMAND)

  • 变量引用:${name}   $name

"":弱引用,其中的变量引用会被替换为变量值

‘‘:强引用,其中的变量引用不会被替换为变量值,而保持原字符串

  • 显示已定义的所有变量:set
  • 删除变量:unset name

环境变量

  • 变量声明、赋值:

export name=VALUE

declare -x name=VALUE

环境变量赋予的值可以传递给子进程,但子进程修改环境变量的值只能往下传递,不能影响父进程的值。(详见附录1.2)

  • 变量引用:$name, ${name}(其中脚本中调用参数超过10使用${name},因为脚本中$10 =$1+0)
  • 显示所有环境变量:

env

printenv

export

declare -x

  • 删除变量:

unset name

  • bash内建的环境变量:

?PATH

?SHELL

?USER

?UID

?HOME

?PWD

?SHLVL(查看shell嵌套深度,详见附录1.3)

?LANG

?MAIL

?HOSTNAME

?HISTSIZE

?_(下划线,上一条命令的参数)

只读和位置变量

  • 只读变量:只能声明,但不能修改和删除

声明只读变量:

readonly name

declare -r name

查看只读变量:

readonly –p

  • 位置变量:在脚本代码中调用通过命令行传递给脚本的参数

$1, $2, ...:对应第1、第2等参数,shift [n]换位置(往前移动几个位置,详见1.6)

$0: 命令本身

$*: 传递给脚本的所有参数,全部参数合为一个字符串

[email protected]: 传递给脚本的所有参数,每个参数为独立字符串

$#: 传递给脚本的参数的个数

[email protected] $* 只在被双引号包起来的时候才会有差异

set -- 清空所有位置变量

(4.10)

退出状态

  • 进程使用退出状态来报告成功或失败

0 代表成功,1-255代表失败

  • $? 变量保存最近的命令退出状态

例如:

ping -c1 -W1 hostdown &> /dev/null

echo $?

退出状态码

  • bash自定义退出状态码

exit [n]:自定义退出状态码

注意:脚本中一旦遇到exit命令,脚本会立即终止;终止退出状态取决于exit命令后面的数字

注意:如果未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态码

算术运算

  • bash中的算术运算:help let

+, -, *, /, %取模(取余), **(乘方)

实现算术运算:

(1) let var=算术表达式

(2) var=$[算术表达式]

(3) var=$((算术表达式))

(4) var=$(expr arg1 arg2 arg3 ...)(详见1.9)

(5) declare –i var = 数值

(6) echo ‘算术表达式’ | bc

  • 乘法符号有些场景中需要转义,如*
  • bash有内建的随机数生成器:$RANDOM(0-32767)

echo $[$RANDOM%50] :0-49之间随机数

赋值

  • 增强型赋值:

+=, -=, *=, /=, %=

  • let varOPERvalue

例如:let count+=3

自加3后自赋值

  • 自增,自减:

let var+=1

let var++

let var-=1

let var--

逻辑运算

  • true, false

1, 0

  • 与:

1 与 1 = 1

1 与 0 = 0

0 与 1 = 0

0 与 0 = 0

  • 或:

1 或 1 = 1

1 或 0 = 1

0 或 1 = 1

0 或 0 = 0

  • 非:!

! 1 = 0

! 0 = 1

  • 短路运算

短路与

第一个为0,结果必定为0

第一个为1,第二个必须要参与运算

短路或

第一个为1,结果必定为1

第一个为0,第二个必须要参与运算

  • 异或:^

异或的两个值,相同为假,不同为真

条件测试

  • 判断某需求是否满足,需要由测试机制来实现

专用的测试表达式需要由测试命令辅助完成测试过程

  • 评估布尔声明,以便用在条件性执行中

若真,则返回0

若假,则返回1

  • 测试命令:

test EXPRESSION

[ EXPRESSION ]

[[ EXPRESSION ]]

注意:EXPRESSION前后必须有空白字符

=~后正则表达式不要加引号

字符串匹配加引号

条件性的执行操作符

  • 根据退出状态而定,命令可以有条件地运行

&& 代表条件性的AND THEN

|| 代表条件性的OR ELSE

例如:

grep -q no_such_user /etc/passwd \

|| echo ‘No such user‘

No such user

ping -c1 -W2 station1 &> /dev/null \

> && echo "station1 is up" \

> || (echo ‘station1 is unreachable‘; exit 1)

station1 is up

test命令

  • 长格式的例子:

test "$A" == "$B" && echo "Strings are equal"

test “$A” -eq “$B” && echo "Integers are equal"

  • 简写格式的例子:

[ "$A" == "$B" ] && echo "Strings are equal"

[ "$A" -eq "$B" ] && echo "Integers are equal"

建议使用简写格式,注意[ 和单词之间有空格。

[ ]里面有东西就为真,但是要用” “把变量引起来才知道有东西。(详见1.12)

bash的数值测试

  • -v VAR

变量VAR是否设置(详见附录1.12)

  • 数值测试:(判断数字大小,两边必须都是数字)

-gt 是否大于

-ge 是否大于等于

-eq 是否等于

-ne 是否不等于

-lt 是否小于

-le 是否小于等于

bash的字符串测试

  • 字符串测试:

== 是否等于

> ascii码是否大于ascii码

< 是否小于

!= 是否不等于

=~ 左侧字符串是否能够被右侧的PATTERN(正则表达式)所匹配(左侧能否包含右侧)正则表达式中变量加引号,字符串不加引号。(详见附录1.13)

注意: 此表达式一般用于[[ ]]中;扩展的正则表达式

[[]]中判断字符串是否相等用==,[]判断字符串是否相等用一个=即可,==也行。这种判断一般一个中括号就行了,两个中括号用于支持正则表达式。

-z "STRING“ 字符串是否为空,空为真,不空为假

-n "STRING“ 字符串是否不空,不空为真,空为假(详见附录1.12)

注意:用于字符串比较时的用到的操作数都应该使用引号

Bash的文件测试

  • 存在性测试

-a FILE:同-e

-e FILE: 文件存在性测试,存在为真,否则为假

  • 存在性及类别测试

-b FILE:是否存在且为块设备文件

-c FILE:是否存在且为字符设备文件

-d FILE:是否存在且为目录文件

-f FILE:是否存在且为普通文件

-h FILE 或 -L FILE:存在且为符号链接文件(详见附录1.15)

-p FILE:是否存在且为命名管道文件

-S FILE:是否存在且为套接字文件

Bash的文件权限测试

  • 文件权限测试:

-r FILE:是否存在且可读

-w FILE: 是否存在且可写

  • -x FILE: 是否存在且可执行(详见附录1.16)
  • 文件特殊权限测试:

-u FILE:是否存在且拥有suid权限

-g FILE:是否存在且拥有sgid权限

-k FILE:是否存在且拥有sticky权限

Bash的文件属性测试

  • 文件大小测试:

-s FILE: 是否存在且非空

  • 文件是否打开:

-t fd: fd 文件描述符是否在某终端已经打开(详见附录1.14)

-N FILE:文件自从上一次被读取之后是否被修改过

-O FILE:当前有效用户是否为文件属主

-G FILE:当前有效用户是否为文件属组

(当前有效用户和实际用户不一定是同一个人,像当前用户执行passwd,当前实际执行的是root权限,当时有效用户变成了root,实际用户是当前用户)

  • 双目测试:

FILE1 -ef FILE2: FILE1是否是FILE2的硬链接

FILE1 -nt FILE2: FILE1是否新于FILE2(mtime)

FILE1 -ot FILE2: FILE1是否旧于FILE2

Bash的组合测试条件

  • 第一种方式:

COMMAND1 && COMMAND2 并且

COMMAND1 || COMMAND2 或者

! COMMAND 非

如:[[ -r FILE ]] && [[ -w FILE ]]

  • 第二种方式:

EXPRESSION1 -a EXPRESSION2 并且

EXPRESSION1 -o EXPRESSION2 或者

! EXPRESSION

必须使用测试命令进行

示例:

[ -z “$HOSTNAME” -o $HOSTNAME "==\

"localhost.localdomain" ] && hostname www.magedu.com

[ -f /bin/cat -a -x /bin/cat ] && cat /etc/fstab

使用read命令来接受输入

  • 使用read来把输入值分配给一个或多个shell变量

-p 指定要显示的提示

-s 静默输入,一般用于密码

-n N 指定输入的字符长度N

-d ‘字符’ 输入结束符

-t N TIMEOUT为N秒

read 从标准输入中读取值,给每个单词分配一个变量

所有剩余单词都被分配给最后一个变量

read -p “Enter a filename: “ FILE

bash如何展开命令行

      (命令运行的过程)

  • 把命令行分成单个命令词
  • 展开别名

      (在脚本中别名不能使用)

  • 展开大括号的声明({})

              echo {1..6}

              1 2 3 4 5 6

  • 展开波浪符声明(~)

              家目录

  • 命令替换$() 和 ``)
  • 再次把命令行分成命令词
  • 展开文件通配(*、?、[abc]等等)
  • 准备I/0重导向(<、>)
  • 运行命令

上面的执行顺序说明的执行的优先级

防止扩展

  • 反斜线(\)会使随后的字符按原意解释

$ echo Your cost: \$5.00

$本身是表示变量的开始符,要原意显示要加\

Your cost: $5.00

  • 加引号来防止扩展

单引号(’)防止所有扩展

双引号(”)也防止所有扩展,但是以下情况例外:

$(美元符号) - 变量扩展

`(反引号) - 命令替换

\(反斜线) - 禁止单个字符扩展

!(叹号) - 历史命令替换

bash的配置文件

  • 按生效范围划分,存在两类:

?全局配置:

/etc/profile

/etc/profile.d/*.sh

/etc/bashrc

?  个人配置:

~/.bash_profile

~/.bashrc

shell登录两种方式

  • 交互式登录:

(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

执行脚本尽量不要使用.或source执行,因为会将原来bash中的相同变量值改变,而用bash或./filename会新开一个bash进程,执行完就退出,不会改变原来的变量值。

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 个历史命令
  • (详见附录1.18)

附录:

1.1 进程树

[[email protected] ~]#ps aux

USER   PID %CPU %MEM    VSZ   RSS TTY  STAT START   TIME COMMAND

root       2058  0.0  0.2 147788  2360 ?        Rs   08:14   0:04  sshd: [email protected]/0

root       2062  0.0  0.2 116292  2796 pts/0    Ss   08:15    0:00   -bash

root       5191  0.0  0.0 107904   612 ?        S    11:15   0:00  sleep 60

root       5198  0.0  0.1 151064  1804 pts/0    R+   11:15   0:00   ps aux

……

查看所有的进程信息

[[email protected] ~]#echo $$

2062

查看当前的进程编号

[[email protected] ~]#pstree -p

           ├─smartd(591)

           ├─sshd(1013)───sshd(2058)───bash(2062)───pstree(5319)

           ├─systemd-journal(357)

           ├─systemd-logind(600)

查看当前的进程树子进程和父进程信息,可以看到pstree是bash的子进程,运行pstree命令,会用bash程序会去解释执行命令

[[email protected] ~]#bash

[[email protected] ~]#echo $$

5498

当前进程号

bash下面bash,bash的子进程bash

[[email protected] ~]#echo $PPID

2062

查看父进程编号

[[email protected] ~]#echo $$

2553

[[email protected] ~]#exit

exit

[[email protected] ~]#echo $$

2039

退出当前进程使用exit命令

[[email protected] ~]#name=`cat /etc/issue`

[[email protected] ~]#echo $name

The hostname is \n Time is \t TTY is \l \S Kernel \r on an \m

[[email protected] ~]#echo "$name"

The hostname is \n

Time is \t

TTY is \l

\S

Kernel \r on an \m

变量是一个很长的文章,需要将变量加上双引号才能按原格式输出

1.2 环境变量

[[email protected] ~]#export var=100

[[email protected] ~]#echo $var

100

[[email protected] ~]#bash

[[email protected] ~]#echo $var

100

[[email protected] ~]#var=200

[[email protected] ~]#bash

[[email protected] ~]#echo $var

200

[[email protected] ~]#exit

exit

[[email protected] ~]#exit

exit

[[email protected] ~]#echo $var

100

可以看出环境变量的赋值只能向下传递,不能向上传递。

1.3 shell嵌套深度

[[email protected] ~]#echo $SHLVL

1

[[email protected] ~]#bash

[[email protected] ~]#echo $SHLVL

2

[[email protected] ~]#bash

[[email protected] ~]#echo $SHLVL

3

查看shell的嵌套深度

1.4 ( )开启新的bash

[[email protected] ~]#( umask 066;touch /app/ff )

[[email protected] ~]#umask

0022

[[email protected] ~]#ls /app

binary  ff  passwd  scripts

命令中的小括号代表新开一个bash,运行完命令后退出新开的bash。

1.5 scp传文件

[[email protected] ~]#scp filename [email protected]:

上传文件到wang的家目录中,密码:magedu

[[email protected] ~]#scp -r [email protected]:/home/wang/scripts  /app/

将远程主机上的文件拷贝到本机上,-r拷贝目录

1.6 脚本中shift作用

[[email protected] /app/scripts]#cat f1.sh

#!/bin/bash

echo "1st is $1"

echo "2st is $2"

echo "3st is $3"

shift

echo "1st is $1"

echo "2st is $2"

echo "3st is $3"

[[email protected] /app/scripts]#./f1.sh a b c

1st is a

2st is b

3st is c

1st is b

2st is c

3st is

使用shift参数往左移动了一位

1.7 上传文件脚本化

[[email protected] /app/scripts]#vim scp14.sh

#!/bin/bash

scp $* [email protected]:

上传代码脚本化

1.8 脚本头自动生成

#!/bin/bash

# create script header automatically

echo "#!/bin/bash

#Filename:     $1

#Author:       sunan

#Date:         `date +%F`

                    ">$1

chmod +x $1

vim + $1

[[email protected] /app/scripts]#./make_script_header.sh  news.sh

脚本头脚本化

1.9 expr计算运算符加空格

[[email protected] /app/scripts]#expr 1+2

1+2

[[email protected] /app/scripts]#expr 1 + 2

3

[[email protected] /app/scripts]#expr 1 * 2

expr: syntax error

[[email protected] /app/scripts]#expr 1 \* 2

2

expr计算需要运算符加空格,*需要转义。

[[email protected] /app/scripts]#expr 1 - 1

0

[[email protected] /app/scripts]#echo $?

1

[[email protected] /app/scripts]#expr 1 - 1

0

[[email protected] /app/scripts]#echo $?

1

[[email protected] /app/scripts]#let 1-1

[[email protected] /app/scripts]#echo $?

1

上面的命令可以正确执行,但返回的执行结果不是0,man expr可以看到:

Exit status is 0 if EXPRESSION is neither null nor 0, 1  if  EXPRESSION

is  null  or  0,  2 if EXPRESSION is syntactically invalid, and 3 if an       error occurred.

1.10 字体加颜色

[[email protected] /app/scripts]#vim color.sh

^[[31mred^[[0m

实现字体加颜色,其中的^[是在vim中使用Ctrl+v+[实现。

[[email protected] /app/scripts]#cat color.sh

red

字体变成红色

1.11 文件加颜色

[[email protected] /app/scripts]#^Mcolor=$[RANDOM%7+31];echo -e "\033[${color}mred color\033[0m"

给文件加颜色

1.12 关于[ ]的判断

[[email protected] /app/scripts]#[ ]&& echo true || echo false

false

[[email protected] /app/scripts]#[ 0 ]&& echo true || echo false

true

[[email protected] /app/scripts]#[ "" ]&& echo true || echo false

false

[[email protected] /app/scripts]#[ " " ]&& echo true || echo false

true

[[email protected] /app/scripts]#a=111

[[email protected] /app/scripts]#[ $a ]&& echo true || echo false  

true

[[email protected] /app/scripts]#unset a

[[email protected] /app/scripts]#[ $a ]&& echo true || echo false

false

[[email protected] /app/scripts]#a=" "

[[email protected] /app/scripts]#[ $a ]&& echo true || echo false

false

[[email protected] /app/scripts]#[ "$a" ]&& echo true || echo false  

true

关于[ ]判断执行成功条件

[[email protected] ~]# var=hh;[ -n $var ]&&echo true || echo false

true

[[email protected] ~]# unset var;[ -n $var ]&&echo true || echo false     

true

[[email protected] ~]# [ -n ]&&echo true || echo false

true

[[email protected] ~]# [ -n  "$var"  ]&&echo true || echo false          

false

当var没有定义,但又没加双引号[ ]判断相当于只有-n存在,就判断为真。

中括号里面当判断的时候,要加双引号。

[[email protected] scripts]# vim useradd.sh

#!/bin/bash

[ $# -ne 1 ] &&echo -e "The arg must one \n Usage:useradd.sh username" && exit 10

id $1 &> /dev/null && echo "$! is exist " && exit 20

useradd $1 && echo "$! is created"

判断用户输入的参数是否等于1,不是退出,是继续下面的命令。

[[email protected] scripts]# var="";[ -v var ]&&echo true ||echo false

true

[[email protected] scripts]# var=ab;[ -v var ]&&echo true ||echo false 

true

[[email protected] scripts]# unset var;[ -v var ]&&echo true ||echo false     

false

只要变量定义了就为真,var前面不需要加$,因为-v 的作用就是直接加var。

[[email protected] scripts]# vim useradd.sh

#!/bin/bash

[ -n “$1”] ||{echo -e "The arg must one \n Usage:useradd.sh username" && exit 10;}

id $1 &> /dev/null && echo "$! is exist " && exit 20

useradd $1 && echo "$! is created"

-n 判断$1是否为空,空就是假执行后面命令,非空为真,跳过后面命令执行下面命令。同时上面必须用{ },( )新开一个子shell,退出是退出一个子shell。

1.13关于[[ ]]的判断

[[email protected] ~]# filename=f1.sh;[[ "$filename" =~ \.sh$ ]] && echo true || echo false

true

[[email protected] ~]# filename=f1.sh;[[ "$filename" =~ "\.sh$" ]] && echo true || echo false

false

和正则表达式做判断时,字符串加引号被认为字符串和引号是一个整体。

[]:单中括号不支持正则表达式

[[email protected] ~]# var="abc*";[[ "$var" == "abc*" ]]&&echo true ||echo false

true

[[email protected] ~]# var="abc*";[[ "$var" == abc* ]]&&echo true ||echo false   

true

[[email protected] ~]# var="abcdef*";[[ "$var" == abc* ]]&&echo true ||echo false

true           #把*当成通配符了

[[email protected] ~]# var="abdef*";[[ "$var" == abc* ]]&&echo true ||echo false

false

工作中最好不要这样用,掌握一个原则:只有用到正则表达式匹配用[[ ]],通常的匹配用[ ]即可,不然容易乱。

[[email protected] ~]# ip=1.1.1.1;[[ "$ip" =~ ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ ]]&&echo true || echo false

true

[[email protected] ~]# ip=1111.1.1.1;[[ "$ip" =~ ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ ]]&&echo true || echo false  

false

判断一个ip地址是否正确

[[email protected] ~]#filename=f1.sh ; [ "$filename" =~  \.sh$  ] && echo true ||echo false

判断后缀

 [[email protected] ~]#var=haha123 ; [[ "$var" =~ ^[0-9]+$  ]] && echo true || echo false

判断数字

 [[email protected] ~]#var=0123 ; [[ "$var" =~ ^0*[1-9][0-9]*$  ]] && echo true || echo false

判断正整数

[[email protected] ~]#mobile=12800138000 ;[[ "$mobile" =~ ^1[3456789][0-9]{9}$  ]] && echo true || echo false

手机号

1.14 文件描述符

面试题:当前这个进程打开了多少个文件?

每打开一个文件就打开一个文件描述符,就是统计文件描述符的个数。

[[email protected] scripts]# ls -l /proc/$$/fd

total 0

lrwx------. 1 root root 64 Nov 25 08:13 0 -> /dev/pts/0

lrwx------. 1 root root 64 Nov 25 08:13 1 -> /dev/pts/0

lrwx------. 1 root root 64 Nov 25 08:13 2 -> /dev/pts/0

lrwx------. 1 root root 64 Nov 25 10:30 255 -> /dev/pts/0

[[email protected] scripts]# ls  /proc/$$/fd | wc -l 

4

[[email protected] scripts]# ls -l /proc/$$/fd | wc -l

5

同时注意加 -l和不加结果不同

1.15 链接文件

[[email protected] scripts]# [ -d /lib ] && echo true

true

[[email protected] scripts]# [ -l /lib ] && echo true

-bash: [: -l: unary operator expected

[[email protected] scripts]# [ -L /lib ] && echo true

true

判断文件属性,需要先判断是不是链接文件,如果是链接文件判断的文件属性石,链接的原文件的属性。

1.16 文件权限判断

[[email protected] scripts]# [ -r /etc/shadow ]&& echo true     

true

[[email protected] scripts]# [ -w /etc/shadow ]&& echo true

true

[[email protected] scripts]# [ -x /etc/shadow ]&& echo true  

[[email protected] scripts]# ll /etc/shadow

----------. 1 root root 1197 Nov  7 17:43 /etc/shadow

判断一个文件的权限不能只看表面的权限,要看实际的最终权限。

1.17 read

[[email protected] scripts]# read

asdf

[[email protected] scripts]# echo $REPLY

asdf

[[email protected] scripts]# read name

abc

[[email protected] scripts]# echo $name

abc

read没有给变量,就赋给了REPLY。

[[email protected] scripts]# read name age title

sunan 26 CTO

[[email protected] scripts]# echo $name $age $title

sunan 26 CTO

赋予多个值,最好一个个赋值。

[[email protected] scripts]# read -s -p "please input your password:" password

please input your password:[[email protected] scripts]#

-s静默模式输入信息后看不到。

[[email protected] ~]#read -n 8 -p "please input your password:" passwd

please input your password:12345678[[email protected] ~]#

-n 规定最多输入几个字符,超过最多的字符数就自动退出。

1.18$-变量

[[email protected] ~]#echo $-

himBH

查看当前启用的功能。

[[email protected] ~]#set +h

[[email protected] ~]#echo $-

imBH

去掉hash功能

[[email protected] ~]#hash

-bash: hash: hashing disabled

[[email protected] ~]#set -h

[[email protected] ~]#hash

hits    command

   1    /bin/cat

   3    /bin/ls

set -h 恢复hash功能的使用

[[email protected] ~]#vim i.sh

#!/bin/bash

echo "$-"

[[email protected] ~]#bash i.sh

hB

在脚本中i功能是被禁用的,i交互式(像别名)。

[[email protected] ~]#echo {1..9}

1 2 3 4 5 6 7 8 9

B大括号扩展功能可以使用

练习:

不想让别的用户登录:生成文件/etc/nologin

以上是关于第九章shell脚本编程基础的主要内容,如果未能解决你的问题,请参考以下文章

Linux应用开发第九章GPIO编程应用开发

Python 编程快速上手 第九章 组织文件

第九章 JQUI

Node入门教程(11)第九章:Node 的网络模块

Python之旅.第九章.并发编程

Python之旅.第九章.并发编程