大数据学习第四天:

大数据学习第四天:

学习主题:shell编程

shell :弱类型、 解释型语言

解释器:shell ,(bash,ksh,zsh)

脚本的执行:当前的shell下启动一个子shell去执行(翻译)脚本

shell 是一个交互性命令解释器。shell独立于操作系统,这种设计让用户可以灵活选择适合自己的shell。shell让你在命令行键入命令,经过shell解释后传送给操作系统(内核)执行。 shell是一个命令处理器(command processor)——是一个读入并解释你输入的命令的程序。除了是一个命令中断器以外,shell还是一个程序设计语言。你可以编写shell可以解释的程序(被称为源程序),这些源程序可以包含shell程序设计命令等等。shell除了解释命令以外,还有其他工作,它也可以配置和编程。 shell拥有自己的语言允许用户编写程序并以一种复杂方式运行。shell编程语言具有许多常用的编程语言的特征,例如:循环和控制结构等。用户可以生成像其他应用程序一样复杂的shell程序。

一.shell变量

shell变量和一些编程语言不同,一般shell的变量赋值的时候不用带“ ” , 而 使 用 或 者 输 出 的 时 候 要 带 “ ”,而使用或者输出的时候要带“ 使”。加减乘除的时候要加两层小括号。括号外面要有一个“ ” , 括 号 里 面 的 变 量 可 以 不 用 “ ”,括号里面的变量可以不用“ ”。需要注意的是,变量赋值,变量使用的时候不能有空格,否则会被解析成命令,报错无此命令。

例子:

#!/bin/bash

a=10
b=20
c=“this is a test”
d= ( ( a + b ) ) e = ((a+b)) e= ((a+b))e=((a-b))
f= ( ( a ∗ b ) ) g = ((a*b)) g= ((ab))g=((a/b))
h= ( ( a i = ((a%b)) i= ((ai=((a**3))

echo c e c h o " a = " c echo "a = " cecho"a="a #输出a的值
echo "b = "KaTeX parse error: Expected 'EOF', got '#' at position 12: b #̲输出b的值 echo "a+b…{d} #输出a+b的值
echo "a-b = "KaTeX parse error: Expected 'EOF', got '#' at position 10: {e} #̲输出a-b的值 echo "a…{f} #输出a*b的值
echo "a/b = "KaTeX parse error: Expected 'EOF', got '#' at position 10: {g} #̲输出a/b的值 echo "a…{h} #输出a%b的值
echo "a^3 = "${i} #输出a的3次方的值

echo "a+b = "KaTeX parse error: Expected 'EOF', got '#' at position 10: ((a+b)) #̲输出a+b的值 echo "a…((a-b)) #输出a-b的值
echo "a*b = "KaTeX parse error: Expected 'EOF', got '#' at position 10: ((a*b)) #̲输出a*b的值 echo "a…((a/b)) #输出a/b的值
echo "a%b = "$((a%b)) #输出a%b的值

echo "a^3 = "$((a**3)) #输出a的3次方的值

echo $((a+b*a-b/a+a%b+a**2)) #表达式可以很长

变量的类型

shell 中有四种类型的变量:用户自定义变量、环境变量、位置参数变量和预定义变量。

1) 用户自定义变量

用户自定义变量只会在当前 shell 中生效,也就是“局部变量”,上面程序中的 name、age、address、money 等都是用户自定义变量,只能在变量所在的那个 shell 脚本中生效。用户自定义变量一般用小写字母来命名。

2) 环境变量

当一个 shell 脚本程序开始执行时,一些变量会根据环境设置中的值进行初始化,这些变量通常用大写字母做名字,以便与用户自定义变量做区分,被称为环境变量。环境变量可以在当前 shell 和这个 shell 的所有子 shell 中生效。如果把环境变量写入相应的配置文件(如 /etc/profile ),那么这个环境变量就会在所有的 shell 中生效。系统自带的环境变量的名字不可更改,但是值可以按需更改。用户也可以使用 export 命令在 shell 中自己创建环境变量:

export 变量名=变量值       # 创建环境变量并赋值

一些主要的系统环境变量如下:

环境变量描述
$HOME当前用户的家目录
$PATH以冒号分隔的用来搜索命令的目录列表,决定了 shell 将到哪些目录中去寻找命令或程序
$PS1命令提示符,通常是 $ 字符,也可以自行设置
$PS2二级提示符,用来提示后续的输入,通常是 > 字符
$IFS输入域分隔符。当 shell 读取输入时,它给出用来分隔单词的一组字符,通常是空格、制表符和换行符
$0shell 脚本的名字
$#传递给脚本的参数个数
$$shell 脚本的进程号(PID),脚本程序通常会用它来生成一个唯一的临时文件,如 /tmp/tmpfile_$$

3) 位置参数变量

位置参数变量主要用来向脚本中传递参数或数据,变量名不能自定义,变量作用也是固定的。主要有以下几种位置参数变量:

位置参数变量描述
$1、$2、…脚本程序的参数,分别代表程序的第1个参数、第2个参数、… 程序第10个以上的参数需要用大括号包含,如 ${10}
$*代表命令行中的所有参数。在一个变量中将所有参数列出,各参数之间用环境变量 IFS 中的第一个字符分隔开。
$@和 $* 一样,也包含了命令行中的所有参数,但是不使用 IFS 环境变量,即使 IFS 为空,参数也是分开显示的

关于 $0 和 $#,在有些资料上,也把这两个归为位置参数变量,本文是把它们归为了环境变量。其中, 0 代 表 s h e l l 脚 本 本 身 ( 不 算 在 参 数 行 列 ) , 0 代表 shell 脚本本身(不算在参数行列), 0shell# 代表传递给脚本的参数个数(不包括 $0)。

关于 $* 和 $@,这二者的区别就在 $* 使用 IFS 所定义的分隔符来分隔参数而 @ 没 有 使 用 。 @ 没有使用。 @使* 将所有的参数视为一个整体,而 $@ 将所有的参数分别视为单独的个体。一般来说,采用 $@ 来访问脚本程序的参数会比较好,不必担心 IFS 所设置的分隔符为空而导致各参数连在一起分不清楚。

4) 预定义变量

预定义变量是在 bash 中已经定义好了的变量,变量名不能自定义,变量作用也是固定的。实际上,位置参数变量就是预定义变量的一种。 除了上面介绍的一些外,这里再介绍两个:

$? :保存最后一次执行的命令的返回状态。如果 $? 的值为 0 ,则表明上一个命令成功执行;如果值非 0 ,则表明上一个命令没有成功执行。

$! :用于保存后运行的最后一个进程的 PID 号。

注意:脚本在执行时都会启动一个子shell进程:

​ 命令行中启动的脚本会继承当前shell环境变量。

​ 系统自动启动脚本(非命令行启动):则需要自我定义环境变量。

* 传递到脚本的参数,与位置变量不同,此选项参数可超过9个

脚 本 运 行 时 当 前 进 程 的 I D 号 , 常 用 作 临 时 变 量 的 后 缀 , 如 h a i s o n . 脚本运行时当前进程的ID号,常用作临时变量的后缀,如 haison. IDhaison.

$! 后台运行的(&)最后一个进程的ID号

@ 与 @ 与 @#相同,使用时加引号,并在引号中返回参数个数

$- 上一个命令的最后一个参数

$? 最后命令的退出状态,0表示没有错误,其他任何值表明有错误

程序有两类返回值:

1、 执行结果 :标准,错误 :标准输出,错误输出

2、 执行状态,$? : 0:表示正确,1-255:错误

输出重定向:

>覆盖重定向

>> 追加重定向

2> 错误覆盖重定向

2>>错误追加重定向

&> 全部重定向

&>> 全部信息追加重定向

撤销变量:

​ unset 变量名

查看shell中变量:

set 命令

查看shell中的环境变量

printenv

env

export

引用变量:${变量名},一般可以省略{}

条件判断,控制结构:

然,在上课时,是通过人的大脑进行判断的;如果在程序语言中,就要通过 if 条件判断语句来判断了。

单分支 if 条件语句

单分支 if 条件语句最为简单,就是只有一个判断条件,如果符合条件则执行某个程序,否则什么事情都不做。语法如下:

if [条件判断式];then
程序
fi

在使用单分支 if 条件查询时需要注意几点:

  • if 语句使用 fi 结尾,和一般语言使用大括号结尾不同。
  • [条件判断式] 就是使用 test 命令判断,所以中括号和条件判断式之间必须有空格。
  • then 后面跟符合条件之后执行的程序,可以放在 [] 之后,用":“分隔;也可以换行写入,就不需要”:"了,比如单分支 if 条件语句还可以这样写:

if [条件判断式]
then
程序
fi

单分支 if 条件语句非常简单,但是千万不要小看它,这是流程控制语句最基本的语法。而且在实现

Linux

管理时,我们的管理脚本一般都不复杂,单分支 if 条件语句使用的概率还是很大的。

举个例子,我想通过脚本判断根分区的使用率是否超过 80%,如果超过 80% 则向管理员报警,请他注意。 脚本就可以这样写:

[root@localhost ~]# df -h

#查看一下服务器的分区状况

文件系统 容量 已用 可用 已用% %挂载点

/dev/sda3 20G 1.8G 17G 10% /

tmpfs 306M 0 306M 0% /dev/shm

/dev/sda1 194M 26M 158M 15% /boot

/dev/srO 3.5G 3.5G 0100% /mnt/cdrom

[root@localhost ~]# vi sh/if1.sh

#!/bin/bash

#统计根分区的使用率

rate=$(df -h | grep “/dev/sda3” | awk ‘{print $5}’ | cut -d"%"-f1)

#把根分区使用率作为变量值赋予变量rate

if [$rate -ge 80 】

#判断rate的值,如果大于等于80,则执行then程序

then

echo 'Warning! /dev/sda3 is full!!"

#打印警告信息。在实际工作中,也可以向管理员发送邮件

fi

其实这个脚本最主要的地方是"rate=$(df-h|grep “/dev/sda3”|awk’{print$5}’|cut-d"%"-f1)“这条命令,我们来分析一下这条命令:先使用"df-h"列出系统中的分区情况;然后使用"grep"命令提取出根分区行;再使用"awk"命令列出第五列,也就是根分区使用率这一列(不过使用率是 10%,不好比较,还要提取出 10 这个数字);最后使用"cut"命令(cut 命令比 awk 命令简单),以”%"作为分隔符,提取出第一列。

这条命令的执行结果如下:

[root@localhost ~]# df -h | grep “/dev/sda3” |awk’{print $5}’|cut -d"%" -f1 10

提取出根分区的使用率后,判断这个数字是否大于等于 80,如果大于等于 80 则报警。至于报警信息,我们在脚本中直接输出到屏幕上。在实际工作中,因为服务器屏幕并不是 24 小时有人值守的,所以也可以给管理员发送邮件,用于报警。

脚本写好之后,就可以利用我们在前面章节中讲到的系统定时任务,让这个脚本每天或几天执行一次,就可以实现自动检测硬盘剩余空间了。后续的系统管理的脚本,如果需要重复执行,则也需要依赖系统定时任务。

双分支条件语句

在双分支 if 条件语句中,当条件判断式成立时,则执行某个程序;当条件判断式不成立时,则执行另一个程序。

语法如下:

if [条件判断式]
then
当条件判断式成立时,执行的程序
else
当条件判断式不成立时,执行的另一个程序
fi

例如,还记得我们在进行条件测试时是怎么显示测试结果的吗?

[root@localhost ~]# [-d /root/sh] && echo “yes” || echo “no”
#第一条判断命令如果正确执行,则打印"yes"; 否则打印"no"
yes

这样显示条件测试的结果还是非常不方便的。当时是因为我们还没有讲 if 语句,所以只能用逻辑与和逻辑或来显示测试结果。既然我们已经学习了 if 语句,就把这个条件测试改写为 if 语句吧。

#!/bin/bash

#判断输入的文件是否是一个目录

read -t 30 -p “Please input a directory:” dir #read接受键盘的输入,并存入dir变量

if[-d $dir]

#测试$dir中的内容是否是一个目录

then

echo “yes”

#如果是一个目录,则输出yes

else

echo “no”

#如果不是一个目录,则输出no

fi

解释一下这个脚本的思路:其实逻辑与和逻辑或也是在判断前一条命令的"$?"的返回值是不是 0,如果是 0,则前一条命令正确执行;如果不是 0,则证明前一条命令执行错误。双分支if条件语句的判断思路也是测试条件判断式是否成立,如果成立,则执行"then"中的命令;如果不成立,则执行"else"中的命令。

多分支 if 条件语句

在多分支 if 条件语句中,允许执行多次判断。也就是当条件判断式 1 成立时,执行程序 1;当条件判断式 2 成立时,执行程序 2;依次类推,当所有条件不成立时,执行最后的程序。语法如下:

if[条件判断式1]
then
当条件判断式1成立时,执行程序1
elif [条件判断式2]
then
当条件判断式2成立时,执行程序2
…省略更多条件…
else
当所有条件都不成立时,最后执行此程序、
fi

例如,用多分支 if 条件语句来判断用户输入的是一个个文件还是一个目录。

[root@localhost ~]#vi sh/if-elif.sh

#!/bin/bash

#判断用户输入的是什么文件

read -p “Please input a filename:” file

#接收键盘的输入,并赋予变量file

if[-z “$file”]

#判断file变量是否为空

then

echo “Error,please input a filename”

#如果为空,则执行程序1,也就是输出报错信息、

exit 1

#退出程序,并定义返回值为1 (把返回值赋予变量$?)

elif[!-e “$file”]

#判断file的值是否存在

then

echo 'Your input is not a file!"

#如果不存在,则执行程序2

exit 2

#退出程序,并定义返回值为2

elif[-f “$file”]

#判断file的值是否为普通文件

then

echo “$file is a regulare file!”

#如果是普通文件,则执行程序3

elif[-d"$file"]

#判断file的值是否为目录文件

then

echo “$file is a directory!”

#如果是目录文件,则执行程序4

else

echo is an other file!"

#如果以上判断都不是,则执行程序5

fi

解释一下脚本思路:这个脚本比较简单,需要说明的是 exit 这条命令。这条命令是退出执行程序的命令,如果符合条件 1(没有输入)和条件 2(输入的不是文件),则需要执行 exit 命令;否则程序还是会运行一下脚本的,这不符合我们的要求。至于 exit 后面的返回值,是自由定义的,主要用于把返回值赋予变量 $?。我们执行一下这个脚本:

[root@localhost ~]# chmod 755 sh/if-elif.sh

#赋予执行权限

[root@localhost ~]# sh/if-elif.sh

#执行脚本

Please input a filename:

#没有任何输入

Error,please input a filename

#报错信息是脚本中自己定义的

[root@localhost ~]# echo $?

1

#变量$?的返回值是我们自己定义的1

[root@localhost ~]# sh/if-elif.sh

Please input a filename: jkgeia

#随便输入不是文件的字符串

Your input is not a file!

#报错信息是自己定义的

[root@localhost ~]# echo $?

2

#变量$?的返回值是我们自己定义的2

逻辑运算来做条件判读 : && 或者 ||

我们在编写脚本中无论如何都少不了逻辑判断,我们通过逻辑判断来进行我们需要进行的操作,完成我们需要的功能。现在我们先看一下最基本的逻辑功能。

true:1;false: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,第二个必须要参与运算

异或(^)

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

[复制代码](javascript:void(0)?

A && B
  当A为0时,不再执行B
  当A为1时,还会执行B
A || B
  当A为1时,不再执行B
  当A为0时,继续执行A
A ^ B
  当A == B,为真
  当A != B,为假

[复制代码](javascript:void(0)?

条件测试

在linux脚本中,我们需要一些工具来帮助我们完成逻辑的判断,通过判断真假条件,在通过逻辑运算符来指定判断出真假后我们需要进一步做些什么,在linux中,有评估布尔声明,以便用在条件执行中:

若真,返回0

若假,返回1

我们一般的判断命令如下:

test expression

[exoression]

[[expression]]

对于这三种判断方法,我们一般使用最多的是后两种

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

示例:

[ “A”“A”" B" ] && echo “Strings are equal”

[ “A"−eq"A"−eq” B" ] && echo “Integers are equal”

[root@CT6 man]# A=23
[root@CT6 man]# B=24
[root@CT6 man]# [ $A -eq $B ] && echo "YES" || echo "NO"
NO
[root@CT6 man]# 

判断一个变量是否设置,如果我们需要用一个变量,但不知道这个变来那个是否存在,我们可以使用-v来判断这个变量是否存在。

[ -v VAR ] && echo “变量存在” || echo “变量不存在”

[root@CT6 man]# set | grep "^A"
[root@CT6 man]# [ -v $A ] && echo "YES" || echo "NO"
YES
[root@CT6 man]# 

数值测试

在脚本中那我们很多时候需要判断数字的大小,而linux中给我们提供了一种判断数字大小的方法,配合条件判断来进行使用:

-gt 是否大于

-ge 是否大于等于

-eq 是否等于

-ne 是否不等于

-lt 是否小于

-le 是否小于等于

示例:

[ 23 –gt 22 ] && echo “true” || echo “false”

[ 66 –ge 66 ] && echo “true” || echo “false”

[root@CT6 man]# [ 23 -gt 22 ] && echo "true" || echo "false" 
true
[root@CT6 man]# [ 66 -ge 66 ] && echo "true" || echo "false" 
true

字符串测试

除了数值测试完,还有字符串测试,用于测试字符是否相同等。

== 是否等于

> ascii码是否大于ascii码

< 是否小于

!= 是否不等于

=~ 左侧字符串是否能够被右侧的PATTERN所匹配

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

[root@CT6 man]# str1=LiuDehua
[root@CT6 man]# str2=LiuDehua
[root@CT6 man]# [ "$str1" == "$str2" ] && echo "=" || echo '!='
=

[复制代码](javascript:void(0)?

[root@CT6 man]# A=string_1234
[root@CT6 man]# [[ $A =~ [[:alpha:]]+[_][0-9]* ]] && echo "匹配" || echo "不匹配"
匹配

[root@CT6 man]# [[ $A =~ ^[[:digit:]] ]] && echo "匹配" || echo "不匹配"     
不匹配

[复制代码](javascript:void(0)?

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

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

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

[复制代码](javascript:void(0)?

[root@CT6 man]# [ -z " " ] && echo "true" || echo "false"
false
[root@CT6 man]# [ -z "" ] && echo "true" || echo "false" 
true
[root@CT6 man]# [ -n "string" ] && echo "true" || echo "false" 
true
[root@CT6 man]# [ -n "" ] && echo "true" || echo "false"      
false

[复制代码](javascript:void(0)?

文件及属性测试

在脚本中我们很多时候要对文件进行处理,那么对文件的判断就显得尤为重要,包括文件是否存在,文件的类型,文件的权限,文件的大小,文件的修改访问时间等,我们通过一定的方式可以实现对文件的各种判断,然后就可以实现我们的目的。

存在性测试

-a FILE:同-e(and也是-a 一般使用-e)

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

[复制代码](javascript:void(0)?

[root@CT6 tmp]# echo 12345 >> test1.txt
[root@CT6 tmp]# ll
total 4
-rw-r--r--. 1 root root 6 Aug 15 15:04 test1.txt
[root@CT6 tmp]# [ -e test1.txt ] && echo "true" || echo "false"
true
[root@CT6 tmp]# rm test1.txt 
rm: remove regular file `test1.txt'? y
[root@CT6 tmp]# [ -e test1.txt ] && echo "true" || echo "false"
false

[复制代码](javascript:void(0)?

存在性及类别测试

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

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

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

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

-h FILE 或 -L FILE:存在且为符号链接文件

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

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

[复制代码](javascript:void(0)?

[root@CT6 tmp]# [ -b /dev/sda ] && echo "YES" || echo "NO"
YES
[root@CT6 tmp]# [ -d /dev ] && echo "YES" || echo "NO"     
YES
[root@CT6 tmp]# [ -h /lib64 ] && echo "YES" || echo "NO"     
NO

[复制代码](javascript:void(0)?

文件权限测试

-r FILE:是否存在且可读

-w FILE: 是否存在且可写

-x FILE: 是否存在且可执行

[复制代码](javascript:void(0)?

[du@CT6 ~]$ cd /tmp/
[du@CT6 /tmp]$ ll
total 0
---x--x--x. 1 root root 0 Aug 15 15:12 du1.doc
--w--w--w-. 1 root root 0 Aug 15 15:12 du2.doc
-rw-r--r--. 1 root root 0 Aug 15 15:12 du3.doc
-rw-r--r--. 1 root root 0 Aug 15 15:12 du4.doc
[du@CT6 /tmp]$ [ -r du1.doc  ] && echo "YES" || echo "NO"
NO
[du@CT6 /tmp]$ [ -r du3.doc ] && echo "YES" || echo "NO" 
YES
[du@CT6 /tmp]$ [ -w du1.doc ] && echo "YES" || echo "NO"  
NO
[du@CT6 /tmp]$ [ -w du3.doc ] && echo "YES" || echo "NO" 
NO
[du@CT6 /tmp]$ [ -w du2.doc ] && echo "YES" || echo "NO" 
YES

[复制代码](javascript:void(0)?

文件特殊权限测试

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

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

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

[复制代码](javascript:void(0)?

[root@CT6 tmp]# ll
total 0
-rwSr-Sr--. 1 root root 0 Aug 15 15:23 lianxi_1.doc
-rwSr--r--. 1 root root 0 Aug 15 15:23 lianxi_2.doc
-rw-r--r-T. 1 root root 0 Aug 15 15:23 lianxi_3.doc
-rw-r--r--. 1 root root 0 Aug 15 15:23 lianxi_4.doc
[root@CT6 tmp]# [ -u lianxi_2.doc ] && echo "YES" || echo "NO"
YES
[root@CT6 tmp]# [ -u lianxi_3.doc ] && echo "YES" || echo "NO" 
NO
[root@CT6 tmp]# [ -k lianxi_3.doc ] && echo "YES" || echo "NO" 
YES
[root@CT6 tmp]# [ -g lianxi_1.doc ] && echo "YES" || echo "NO"   
YES

[复制代码](javascript:void(0)?

文件大小测试

-s FILE: 是否存在且非空

[复制代码](javascript:void(0)?

[root@CT6 tmp]# touch tty1
[root@CT6 tmp]# echo qqq > tty2
[root@CT6 tmp]# [ -s tty1 ] && echo "NOT empty" || echo "empty"
empty
[root@CT6 tmp]# [ -s tty2 ] && echo "NOT empty" || echo "empty" 
NOT empty

[复制代码](javascript:void(0)?

文件是否打开

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

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

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

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

[复制代码](javascript:void(0)?

[root@CT6 tmp]# [ -O tty2 ] && echo "YES" || echo "NO"             
YES
[root@CT6 tmp]# [ -G tty2 ] && echo "YES" || echo "NO" 
YES
[root@CT6 tmp]# ll
total 8
-rw-r--r--. 1 root root    0 Aug 15 15:27 tty1
-rw-r--r--. 1 root root    4 Aug 15 15:27 tty2

read命令

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

-p 指定要显示的提示

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

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

-d ‘字符’ 输入结束符

-t N TIMEOUT为N秒

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

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

read -p “Enter a filename: “ FILE

一般用于脚本中

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类和bashrc类

profile类:为交互式登录的shell提供配置

全局: /etc/profile, /etc/profile.d/*.sh

个人: ~/.bash_profile

功用:

(1) 用于定义环境变量

(2) 运行命令或脚本

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 个历史命令

[复制代码](javascript:void(0)?

[root@CT6 tmp]# echo $-
himBH
[root@CT6 tmp]# set +h
[root@CT6 tmp]# echo $-
imBH
[root@CT6 tmp]# set +B
[root@CT6 tmp]# echo $-
imH

一、for循环
1.数字段形式

代码如下:


 for i in {1..10}
 do
    echo $i
 done

2.详细列出(字符且项数不多)

代码如下:
$$

$$

 for File in 1 2 3 4 5 
 do 
     echo $File 
 done

3.对存在的文件进行循环

代码如下:

for shname in ls *.sh
do
​ name=echo "$shname" | awk -F. '{print $1}'
​ echo $name
done

4.查找循环(ls数据量太大的时候也可以用这种方法)

复制代码 代码如下:

for shname in find . -type f -name "*.sh"
do
​ name=echo "$shname" | awk -F/ '{print $2}'
​ echo $name
done

5.((语法循环–有点像C语法,但记得双括号

复制代码 代码如下:

 for((i=1;i<100;i++))
 do
     if((i%3==0))
     then
         echo $i
         continue
     fi
 done
 

6.seq形式 起始从1开始

复制代码 代码如下:

for i in seq 100
do
​ if((i%3==0))
​ then
​ echo $i
​ continue
​ fi
done

二、while循环

1.while循环注意为方括号[],且注意空格

代码如下:

min=1
max=100
while [ min -le max ]
do
​ echo $min
​ min=expr $min + 1
done

2.双括号形式,内部结构有点像C的语法,注意赋值:i= ( ( (( ((i+1))

代码如下:

 i=1
 while(($i<100))
 do
     if(($i%4==0))
     then
         echo $i
     fi
     i=((i+1))
 done

3.从配置文件读取,并可以控制进程数量

代码如下:

 MAX_RUN_NUM=8
 cat cfg/res_card_partition.cfg |grep -v '^$'|grep -v "#" | grep -v grep |while read partition 
 do        
                 nohup sh inv_res_card_process.sh partition >log/resCardpartition.log 2>&1 &               
                 while [ 1 -eq 1 ]
                 do
                                 psNum=`ps -ef | grep "inv_res_card_process" | grep -v "grep" | wc -l`
                                 if [ psNum -ge MAX_RUN_NUM ]
                                 then
                                               sleep 5
                                 else
                                               break
                                  fi                                        
                 done                
 done

三.循环控制语句

 \# break 命令不执行当前循环体内break下面的语句从当前循环退出. 
 \# continue 命令是程序在本循体内忽略下面的语句,从循环头开始执行

case语句使用于需要进行多重分支的应用情况

格式:

[复制代码](javascript:void(0)?

case $变量名 in
 模式1)
 命令序列1
 ;;
 模式2)
 命令序列2
 ;; 
 *)
 默认执行的命令序列     
 ;; 
esac 

[复制代码](javascript:void(0)?

[复制代码](javascript:void(0)?

case语句结构特点如下:
case行尾必须为单词 in 每个模式必须以右括号 ) 结束
双分号 ;; 表示命令序列结束
case语句结构特点如下:
匹配模式中可是使用方括号表示一个连续的范围,如[0-9];使用竖杠符号“|”表示或。
最后的“*)”表示默认模式,当使用前面的各种模式均无法匹配该变量时,将执行“*)”后的命令序列。

inux shell 可以用户定义函数,然后在shell脚本中可以随便调用。下面说说它的定义方法,以及调用需要注意那些事项。

一、定义shell函数(define function)

linux shell 可以用户定义函数,然后在shell脚本中可以随便调用。

语法:

[ function ] funname [()]

{

​ action;

​ [return int;]

}

说明:

1、可以带function fun() 定义,也可以直接fun() 定义,不带任何参数。

2、参数返回,可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值。 return后跟数值n(0-255

实例(testfun1.sh):

`#!/bin/sh`` ` ` ``fSum 3 2;`` ``function` `fSum()`` ``{``     ``echo` `$1,$2;``     ``return` `$(($1+$2));`` ``}`` ``fSum 5 7;`` ``total=$(fSum 3 2);`` ``echo` `$total,$?;``                 ` `sh testfun1.sh``testfun1.sh: line 3: fSum: ``command` `not found``5,7``3,2`

从上面这个例子我们可以得到几点结论:

1、必须在调用函数地方之前,声明函数,shell脚本是逐行运行。不会像其它语言一样先预编译。一次必须在使用函数前先声明函数。

2、total=$(fSum 3 2); 通过这种调用方法,我们清楚知道,在shell 中 单括号里面,可以是:命令语句。 因此,我们可以将shell中函数,看作是定义一个新的命令,它是命令,因此 各个输入参数直接用 空格分隔。 一次,命令里面获得参数方法可以通过: 0 … 0… 0n得到。 $0代表函数本身。

3、函数返回值,只能通过 ? 系 统 变 量 获 得 , 直 接 通 过 = , 获 得 是 空 值 。 其 实 , 我 们 按 照 上 面 一 条 理 解 , 知 道 函 数 是 一 个 命 令 , 在 s h e l l 获 得 命 令 返 回 值 , 都 需 要 通 过 ? 系统变量获得,直接通过=,获得是空值。其实,我们按照上面一条理解,知道函数是一个命令,在shell获得命令返回值,都需要通过 ?=,shell?获得。

二、函数作用域,变量作用范围

先我们看一个实例(testfun2.sh ):

`#!/bin/sh` `echo` `$(``uname``);``declare` `num=1000;` `uname``()``{``    ``echo` `"test!"``;``    ``((num++));``    ``return` `100;``}``testvar()``{``    ``local` `num=10;``    ``((num++));``    ``echo` `$num;` `}` `uname``;``echo` `$?``echo` `$num;``testvar;``echo` `$num;``               ` `                              ` `sh testfun2.sh``Linux``test``!``100``1001``11``1001`

我们一起来分析下上面这个实例,可以得到如下结论:

1、定义函数可以与系统命令相同,说明shell搜索命令时候,首先会在当前的shell文件定义好的地方查找,找到直接执行。

2、需要获得函数值:通过$?获得

3、如果需要传出其它类型函数值,可以在函数调用之前,定义变量(这个就是全局变量)。在函数内部就可以直接修改,然后在执行函数就可以读出修改过的值。

4、如果需要定义自己变量,可以在函数中定义:local 变量=值 ,这时变量就是内部变量,它的修改,不会影响函数外部相同变量的值 。

Shell echo命令

Shell 的 echo 指令与 PHP 的 echo 指令类似,都是用于字符串的输出。命令格式:

echo string

您可以使用echo实现更复杂的输出格式控制。

1.显示普通字符串:

echo "It is a test" 

这里的双引号完全可以省略,以下命令与上面实例效果一致:

echo It is a test

2.显示转义字符

echo "\"It is a test\""

结果将是:

"It is a test" 

同样,双引号也可以省略

3.显示变量

read 命令从标准输入中读取一行,并把输入行的每个字段的值指定给 shell 变量

#!/bin/sh
read name 
echo "$name It is a test" 

以上代码保存为 test.sh,name 接收标准输入的变量,结果将是:

[root@www ~]# sh test.sh
OK                     #标准输入
OK It is a test        #输出 

4.显示换行

echo -e "OK! \n" # -e 开启转义
echo "It is a test" 

输出结果:

OK!

It is a test

5.显示不换行

#!/bin/sh
echo -e "OK! \c" # -e 开启转义 \c 不换行
echo "It is a test"

输出结果:

OK! It is a test

6.显示结果定向至文件

echo "It is a test" > myfile 

7.原样输出字符串,不进行转义或取变量(用单引号)

echo '$name\"'

输出结果:

$name\" 

8.显示命令执行结果

echo `date` 

注意: 这里使用的是反引号 `, 而不是单引号 '。

结果将显示当前日期

Thu Jul 24 10:08:46 CST 2014
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值