Linux基础(五)

一、shell编程基础

1、shell编程

程序=指令+数据

编程风格:

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

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

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

2、路径设置

export $PATH:/root

export $PATH:. shell脚本到哪儿都能执行(不建议)很危险

vim .bash_profile

生效:. .bash_profile

source .bash_profile

问题:当我创建一个shell文件之后,当移动着个文件后,发现他任然在找/root/bash(之前设置了PATH路径),原因是?

答:因为hash值的原因,外部命令第一次执行时搜索的路径会记录在内存的hash表中

hash查看一下,会发现有/root/first.sh

清除一下:hash -d first.sh

问题: 脚本执行,命令错误,继续执行

脚本执行,语法错误,终止执行

bash -n 语法检查,但不检查命令错误

bash -x 查看执行过程,跟踪调试

pstree :查看进程树 pstree -p

$$:可以查看当前进程id号

PS2 : 多行提示符

3、变量赋值:

name="String" #加入多行文件时加""会保留原格式(name=`cat /etc/issue` echo "$name")

cmd=hostname--> echo $cmd --> centos7.3.vincent

4、变量调用:

$ : $name

子:

vim par.sh

#!/bin/bash

name="par"

echo "par pid is $$"

echo "par.sh:name=$name"

/bin/bash son.sh /root/sun.sh . /root/sun.sh

echo "son.sh:name=$name"

vim son.sh

#!/bin/bash

export name

#name="son"

echo "son pid is $$"

echo "son.sh:name=$name"

结果:子进程的变量只在子进程中有效

从上面的例子中,我们能够得出:./ /bin/bash source三种执行方式的不同

./ 与 /bin/bash 都是新开进程,进行执行,此时本地变量不会被继承,不改变当前环境,通常用于执行脚本文件

source 与 . 则是将子进程放到父进程进行执行,将影响当前环境,常用于读取配置文件

5、bash中变量分类、

本地变量(普通变量):生效范围为当前shell,对当前shell之外的其他shell进程,包括当前shell的子进程均无效

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

局部变量:生效范围为当前shell进程中某代码片段

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

特殊变量:$?,$0,$*,$@,$#,$$

(1)声明环境变量

export name=VALUE

declare -x name=VALUE

(2)查看环境变量

env

declare -x

printenv

export

(3)本地变量赋值

name = 'value'

(4)可以使用引用value

(1)可以是直接字符串:name = "root"

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

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

(5)变量引用:$ $name

"":弱引用,其中的变量引用会被替换成变量名

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

(6)显示自己定义的所有变量

set :显示出所有的变量包括一些函数

(7)删除变量

unset 变量名,...

(8)显示上一条命令执行情况

echo $? :返回上一个执行的结果,通常0为正确,1为错误(这个值不是固定的,可自己指定1-255)

(9)只读变量和位置变量

只读变量:只能声明,但不能删除和修改( 进程的声明周期 )

声明:readonly name

declare -r name declare -ir name ( i表示数字 )

查看:readonly -p

例如:PI = 3.1415926

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

$1,$2,$3,...对应第一,第二...参数,shift [n] 换位置 [ $10 ,$ ]

$0 :命令本身

$* :传递给脚本的所有参数,全部参数合为一个字符串( "string1 string2....")

$@ :传递给脚本的所有参数,每个参数为独立字符串 ( "string1" "string2" "string3" ... )

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

$@ $* :只有在被双引号引起来的时候才会有差异

说明:在编写脚本时,进来先判断

[ $# -lt 1 ] && echo "Usage:$0 arg1..." && exit 0

位置变量注意点:

当引用参数大于10个时,我们在用$10,$11这种做法就不行,会出现错误,此时需要使用 $,$,......

清空位置变量

set --

位置变量的扩展功能(执行一次,移动一位,只使用$1就好)

但我们在执行一个程序时,如何判断其是否执行完,我们可以通过shift来看看

shift N(N值很大,超过了给定变量的总数),如果执行完了,就会返回相应的错误代码

6、算术运算

查看bash中算术运算:help let

常用算术运算符:+、-、*、/、%、**(乘方)

算术运算实现:

1 let var=算术表达式

注意: let i=0 -> echo $? --->1

k=0 --> let k++ -->echo $? 1

k=0 --> let ++k -->echo $? 0

2 var=$[算术表达式]

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

4 var=$(expr arg1 arg2 arg3...)

5 declare -i var = 数值

6 echo '算术表达式' bc

算术运算中注意事项

乘法符号有些场景中需要转义,如*

bash有内建的随机数生成器:$RANDOM(1-32767)

echo $[$RANDOM%50] :生成1-49之间随机数

7、逻辑运算

布尔值

true、false

1 0

见0为0

见1为1

异或

相同为0,不同为1

用于交换两数的值

短路

aa && bb aa为假则结束运算 (qq执行成功,则执行bb命令)

aa bb aa为真则结束运算 (aa命令失败,则执行bb命令)

实例:

1、判断用户存在否,在则返回用户名否则创建该用户

id $name &> echo $name is exist useradd $name

2、ping某主机,通则打印up否则down

ping -w1 -c1 172.18.0.1 &> /dev/null && echo "The machine is up" echo "The machie is down"

8、退出状态

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

0 --> 代表成功

1-255 --> 代表失败

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

实例

$ ping -c1 -w1 hostname &> /dev/null-c:ping的次数 -w:几秒ping一次

$?

退出状态码

bash自定义退出状态码

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

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

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

9、条件测试

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

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

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

若真,则返回0

若假,则返回1

测试命令

test EXPRESSION

长格式:

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

$ test "$A" -eq "$B" && echo "Integres are equal"

短格式:

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

$[ "$A" -eq "$B" ] && echo "Integres are equl"

空值或不赋值时是假 test $var && echo true

var="" test $var && echo true #结果都是假

var=" " test $var && echo true #结果为真

[ EXPRESSION ]

实例:判断一个文件是否存在,存在则退出

[ ! -e $1 ] && echo "The file not exist" && exit

[ -e $1 ] (echo "$1 is not exit " && exit) (这一条语句逻辑是不正确的,exit只是退出了子shell、子进程,并没有退出判断条件开启的shell)

改进:[ -e $1 ] { echo "$1 is not exit " ;exit;}(使用了匿名函数)

[[ EXPRESSION ]][[ ]]才支持正则表达式写法

注意:EXPRESION前后必须有空白字符,[ 是一个内部命令,[[ 是关键字

查帮助

help test

条件性的执行操作符

&& :代表条件性的AND THEN

:代表条件新的OR ELSE

实例:aa && bb cc :选择表达式

ping -c1 -w1 172.18.0.1 &> /dev/null && the host is up the host is down

read -p "Please enter a dirname:" fileuse

filename=${$fileuse:-"filename"}

=========================================================================================

变量赋值方式 变量y没有设置 变量y为空值 变量yshezho

x=$ x=新值 x=空 x=$y

x=$ x=新值 x=新值 x=$y

-------------------------------------------------------------------------------------

x=$ x=空 x=新值 x=新值

x=$ x=空 x=空 x=新值

--------------------------------------------------------------------------------------

x=$ x=新值 x=空 x=$y

y=新值 y值不变 y值不变

-------------------------------------------------------------------------------------

x=$ x=新值 x=新值 x=$y

y=新值 y=新值 y值不变

--------------------------------------------------------------------------------------

x=$ 新值输出到标准错误输出 x=空 x=$y

x=$ 新值输出到标准错误输出 新值输出到标准错误输出 x=$y

======================================================================================

10、比较运算符

(1)文件判断

-d filename:判断该文件是否存在,并且是否为目录文件

-e filename:判断文件是否存在(等价-a)d

-f filename:判断该文件是否存在,并且是否为普通文件

-b (你对软连接进行判断时,它判断的是软连接指向的文件( [ -b /dev/cdrom ] && exit 0)

-L 判断链接文件本身是什么文件( -h 存在且为符号链接文件)

-p 管道文件

-S 套接字文件

-s 大小为0

-r filename:...并且该文件是否拥有读权限(该权限是实际权限,而不是ll显示的权限,Acl权限)

-w

-x

-u filename :...是否拥有SUID权限【作用在二进制程序上,对目录无效】(passwd命令 chmod 4755添加suid权限)

-g (chmod 2755 )

-k (chmod o+t)

注意:在判断文件类型时,先判断软连接文件,在判断其他文件。软连接文件指向其真实的文件会先判断

(2)文件测试

文件大小测试:

-s file:是否存在且非空

文件是否打开

-t fd :fd表示文件描述符是否已经打开且与某终端相关

-N file:文件自动上一次被读取之后是否被修改过(即:修改时间是否比读的时间新)

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

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

双目测试

file1 -ef file2 :file1和file2是否指向同一个设备上的相同inode(判断硬链接)

file1 -nt file2 :file1 是否新于file2

file1 -ot file2 :file1是否旧于file2

(3)文件比较

file1 -nt file2:判断file1的修改时间是否比file2新

file1 -ot file2:...旧

file1 -ef file2:判断file1与file2的inode号是否相同(可理解为两文件是否为同一个文件,用于判断硬链接)

文件判断:

[[ "$sum" =~ ^.*\.sh$ ]] && echo $num is script $num is not script

(4)数字比较

-eq :判断是否相等

-ne :判断是否不相等

数字判断:

[[ "$sum" =~ ^-?[0-9]+$ ]] && echo $num is number $num is not number

(5)字符串比较

-z "string":判断字符串是否为空 ,空为真(变量加引号)

-n "string":判断字符串是否为非空,非空为真

test -n "$abc" && echo true

test -n && echo true #结果为真

== :判断两字符串是否相等

!= :判断两字符串是否不相等

> :ascii码1是否大于ascii码2

=~ :左侧字符串是否能够被右侧的PATTERN所匹配(左侧的字符串是否包含右侧pattern)

str=abc

[[ "$str" =~ "abc" ]] && echo true echo false

[[ $str =~ a.c ]] && echo true echo false(判断是否包含a,c不需要加引号)

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

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

实例:

-z:True is string is empty

x=100 --> [ -z $x ] --> echo $? --> 1 : -z为空则真,

uset x--> [ -z $x ] --> echo $? --> 1 :-z非空则假,

-n:True in string is not empty

x=100 --> [ -n $x ] --> echo $? --> 1 :

uset x--> [ -n $x ] --> echo $? --> 1 :

x=100 --> [[ -n $x ]] --> echo $? --> 0 (使用[[ ]]才能看到正确结果)

(6)多重条件判断

判断1 -a 判断2 :逻辑与,1,2都成立,结果为真

判断1 -o 判断2 :逻辑或,1个成立结果为真

!判断 :逻辑非,原始的判断式取反

查看进程:

pstree -p

echo $$ :查看当前进程编号

echo $PPIP :查看父进程的进程号

判断一个文件是否以.txt结尾 ( ~ 表示后面跟正则表达式)

[[ $file =~ txt ]] && echo true

(7)组合测试表达式

第一种方法

command1 && command2 并且

command1 command2 或者

!command (!true 与 [ !true ]是不一样的)

第二种方式:

EXPRESSION1 -a EXPRESSION2 并且

EXPRESSION1 -o EXPRESSION2 或者

!EXPRESSION

必须使用测试命令进行

实例:

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

如何判断输入的是数字

方法一

m=10

expr $m + 0

方法二

利用正则表达式

(8)总结:

1、那些括号的灵活使用

[表达式] test

( ) 开子进程

x=abc;echo $$;(echo $$ ;echo $x ;sleep 100; x=def ;echo $x );echo $x 【()开了子进程,sleep在子进程下再开进程执行】

结果:abc def abc

{ cmd1,cmd2,cmd3.... } 不开子shell。相当于顺序执行

x=abc;echo $$;;echo $x

结果:abc def def

11、I/O操作

1、read命令来接收键盘输入

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

-p 指定要显示的提示

-s 静默模式

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

-d '字符' 输入结束符

-t N Timeout为n秒

read 从标准输入中读取值,给每个单词分配一个变量,所有剩余单词都被分配给最后一个变量

read -p "Enter a filename: " filename

实例

read n < /etc/issue--->echo $n ---->honstname is \n

read a b c echo $b yyy -->echo $c zzz

read m n l

12、bash中如何展开命令行

把命令行分成单个命令词

展开别名

展开大括号中的声明{}

展开波浪符声明~

命令替换$()和``

再次把命令行分成命令词

展开文件通配符(*、?、[abc]等)

准备I/O重定向()

运行命令

防止扩展

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

$echo Your cost:\$5.00

Your cost:$5.00

加引号来防止扩展

单引号('')防止扩展

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

$ ----> 变量扩展

``(反引号)->命令替换

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

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

13、bash的配置文件

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

全局配置

/etc/profile

/etc/profile.d/*.sh

/etc/bashrc

个人配置:

~/.bash_profile

~/.bashrc */

14、shell登录两种方式

交互式登录:

(1)直接通过终端输入账号密码登录

(2)使用 "su - UserName "切换用户

执行顺序

/etc/profile --> /etc/profile.d/*.sh(登录就会执行,如果你想要配置的服务开机执行什么脚本就可以放在这里)*/ --> ~/.bash_profile (放环境变量)--> ~/.bahsrc (别名、本地变量)--> /etc/bashrc(靠后的生效)

非交互式登录

(1)su UserName

(2)图形界面下打开的终端

(3)执行脚本

执行顺序

~/.bashrc(别名和函数本地变量) --> /etc/bashrc --> /etc/profile.d/*.sh

.bash_profile:定义环境变量和开机启动项

source (.) scriptnaem 在当前shell执行*/

/bin/bash ./ 不开子进程执行

退出执行

/etc/bash_logout 退出的时候自动执行的文件,可在该文件中添加操作,当你退出时便会执行(rm -rf /app/* 当你退出时便会清空/app目录)*/

二、shell编程进阶

/etc/profile/vim.sh

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180101G00AP300?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

同媒体快讯

扫码关注云+社区

领取腾讯云代金券