编程基础:
程序:指令+数据
程序编程风格:
过程式:以指令为中心,数据服务于指令。 小软件过程,大软件对象。
对象式:以数据为中心,指令服务于数据
shell程序:提供了编程能力,解释执行
shell脚本基础:
shell脚本:
包含一些命令或声明,并符合一定格式的文本文件
格式要求:首行shebang机制
#!/bin/bash
#!/usr/bin/python
#!/usr/bin/perl
shell脚本的用途有:
自动化常用命令
执行系统化管理和故障排除
创建简单的应用程序
处理文本或文件
创建shell脚本
第一步:使用文本编辑器来创建文本文件
第一行必须包括shell声明序列:#!
#!/bin/bash
添加注释
注释以#开头
第二步:运行脚本
给予执行权限,在命令行上指定脚本的绝对或相对路径
直接运行解释器,将脚本作为解释器程序的参数运行
脚本规范:
脚本代码开头约定:
1、第一行一般为调用使用的语言
2、程序名,避免更改文件名为无法找到正确的文件
3、版本号
4、更改后的时间
5、作者相关信息
6、该程序的作用,及注意事项
7、最后是各版本的更新简要说明
脚本的基本结构:
脚本的基本结构
#!SHEBANG
CONFIGURATON_VARIABLES
FUNCTION_DEFINITIONS
MAIN_CODE
shell脚本示例
#!/bin/bash
# ------------------------------------------
# Filename: hello.sh
# Revision: 1.1
# Date: 2017/06/01
# Author: wang
# Email: wang@gmail.com
# Website: www.magedu.com
# Description: This is the first script
# ------------------------------------------
# Copyright: 2017 wang
# License: GPL
echo “hello world”
脚本调试
检测脚本中的语法错误
bash -n /path/to/some_script
调试执行
bash -x /path/to/some_script
bash -n 只能检查语法错误
变量
变量:命名的内存空间
数据存储方式:
字符:
数值:×××,浮点型
变量:变量类型
作用:
1、数据存储格式
2、参与的运算
3、表示的数据范围
类型:
字符
数值:×××、浮点型
加" "可以改变格式 如: echo="name"
变量:
强类型:变量不经过强制转换,它永远是这个数据类型,不允许隐式的类型转
换。一般定义变量时必须制动类型、参与运算必须符合类型要求;调用未声明
变量会产生错误
如 java,c#
弱类型:语言的运行时回隐形做数据类型转换。无须指定类型,默认均为字符型;
参与运算会自动进行隐式类型转换;变量无需事先定义可直接调用
如:bash不支持浮点数,php 可以用数字但是不能放在前面
变量命名法则:
1、不能使程序中的保留字:列如if,for
2、只能使用数字、字母及下划线,且不能以数字开头
3、见名知义
4、统一命名法则:骆峰命名法:把多个首字母大写,小驼峰:第一个首字母大写,
bash中变量的种类:
根据变量的生效范围等标准划分下面变量类型:
局部变量:生效范围为当前shell进程;对当前shell之外的其他shell进程,包括
当前shell的子shell进程均无效
环境变量:生效范围为当前shell进程及其子进程
本地变量:生效范围为当前shell进程中某代码片段,通常指函数
位置变量:$1,$2,...来表示,用于让脚本在脚本代码中调用通过命令行传递给它
的参数
特殊变量:$>,$0,$@,$#,$$
局部变量:
echo $$
echo $PPID:父子进程
局部变量只能在当前shell有效
在下级子进程变量不能往上传别的进程
全局变量:使用要加关键字 export :把当前变量转换环境变量
它允许往下传 父进程可以传给子进程
bash 后台执行
declare -x 也可以生成所有环境变量
env也能显示环境变量
unset name 删除当前环境变量
set :本剧变量 全局变量都有
常量:固定值
readonly -p:显示常量
():用于一次性任务 执行一个小subsheell 不影响环境,
{}:和小括号有区别
位置变量:能让脚本写死
$1 $2 $3
1 存的就是第一个字符串
10 个以上就得用{}
如:e‘cho "ALL args are {$10}"
scp :可以远程复制
scp.sh
shift:从右往左挤掉
ping -c:指定网络拼一次
总结:
shell
变量:局部和环境 $1,$@ $*,$#,$0
set unset exprot declare -i -r -x env
环境变量:
变量声明、赋值:
export name=VALUE
declare -x name=VALUE
变量引用:$name,${name}
显示所有环境变量:
env
printenv
export
declare -x
删除变量:
unset name
环境变量:
bash内建的环境变量:
PATH
SHELL
UID
USER
HOME
PWD
SHLVL
LANG
MAIL
HOSTNAME
HISTSIZE
—:下划线
只读和位置变量:
只读变量:只能声明,但不能修改和删除
声明只读变量:
readonly name
declare -r name
查看只读变量:
readonly -p
位置变量:在脚本代码中调用命令行传递给脚本的参数
$1,$2,...:对应第1,第2等参数,shift [n]换位置
$0:命令本身
$*;传递给脚本的所有参数,全部参数合为一个字符串
$@:传递给脚本的所有参数,每个参数为独立字符串
$#:传递给脚本的参数的个数
$@$*只在被双引号抱起来的时候才会有差异
set -- 清空所有位置变量
退出状态:
进程使用退出状态来报告成功或失败
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...)
5、declare -i var =数值
6、echo ‘算数表达式‘ | bc
乘法符号有些场景中需要转义,如*
bash有内建的随机数生成器:$RANDOM(0-32767)
echo $[$RANDOM%50】 :0-49之间随机数
赋值:
增强型赋值:
+=,-=,*=,/=,%=
let varOPERvare
列如:let count+=3
自加3后减值
自增,自减:
let var+=1
let var++
let var-=1
let var--
逻辑运算;
true,false
1,0
与:
1与1=1 & 并且 and
1与0=0 | 或者 or
0与1=0 cmd1 && cmd2 如果cmd1为假,cmd2不需要执行,反之cmd1为真,需要cmd2执行
0与0=0 cmd1 || cmd2如果为真,cmd2不需要执行,反之cmd1为假,需要cmd2执行
或: XOR 异或
1或1=1 0^1=1
1或0=1 0^0=0
0或1=1 1^0=1
0或0=0 1^1=0
逻辑运算:
非:!
!1=0
!0=1
短路运算:
短路与
第一个为0,结果必定为0
第一个为1,第二个必须要参与运算
短路或
第一个为1,结果必定为1
第一个为0,第二个必须要参与运算
异或:^
异或的两个值,相同为假,不必为真
条件测试;
判断某需求是否满足,需要由测试机制来实现
专用的测试表达式需要由测试命令辅助完成测试过程
评估布尔声明,以便用条件执行中
若真,泽返回0
若假,则返回1
测试命令:
testEXPRESSION
[ EXPRESSION]
[[ EXPRESSION]]
注意:EXPRESSUON前后必须有空白字符
条件性的执行操作符:
根据退出状态而定,命令可以有条件地运行
&&代表条件行的AN 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"
bash的数值测试
?-v VAR
变量VAR是否设置
?数值测试:
-gt 是否大于
-ge 是否大于等于
-eq 是否等于
-ne 是否不等于
-lt 是否小于
-le 是否小于等于
bash的字符串测试
?字符串测试:
== 是否等于
> ascii码是否大于ascii码
< 是否小于
!= 是否不等于
=~ 左侧字符串是否能够被右侧的PATTERN所匹配
注意: 此表达式一般用于[[ ]]中;扩展的正则表达式
-z "STRING“ 字符串是否为空,空为真,不空为假
-n "STRING“ 字符串是否不空,不空为真,空为假
? 注意:用于字符串比较时的用到的操作数都应该使用引号
Bash的文件测试
?存在性测试
-a FILE:同-e
-e FILE: 文件存在性测试,存在为真,否则为假
?存在性及类别测试
-b FILE:是否存在且为块设备文件
-c FILE:是否存在且为字符设备文件
-d FILE:是否存在且为目录文件
-f FILE:是否存在且为普通文件
-h FILE 或 -L FILE:存在且为符号链接文件
-p FILE:是否存在且为命名管道文件
-S FILE:是否存在且为套接字文件
Bash的文件权限测试
?文件权限测试:
-r FILE:是否存在且可读
-w FILE: 是否存在且可写
-x FILE: 是否存在且可执行
?文件特殊权限测试:
-u FILE:是否存在且拥有suid权限
-g FILE:是否存在且拥有sgid权限
-k FILE:是否存在且拥有sticky权限
Bash的文件属性测试
?文件大小测试:
-s FILE: 是否存在且非空
?文件是否打开:
-t fd: fd 文件描述符是否在某终端已经打开
-N FILE:文件自从上一次被读取之后是否被修改过
-O FILE:当前有效用户是否为文件属主
-G FILE:当前有效用户是否为文件属组
Bash的文件属性测试
?双目测试:
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如何展开命令行
?把命令行分成单个命令词
?展开别名
?展开大括号的声明({})
?展开波浪符声明(~)
?命令替换$() 和 ``)
?再次把命令行分成命令词
?展开文件通配(*、?、[abc]等等)
?准备I/0重导向(<、>)
?运行命令
防止扩展
?反斜线(\)会使随后的字符按原意解释
$ echo Your cost: \$5.00
Your cost: $5.00
?加引号来防止扩展
? 单引号(’)防止所有扩展
? 双引号(”)也防止所有扩展,但是以下情况例外:
?$(美元符号) - 变量扩展
?`(反引号) - 命令替换
?\(反斜线) - 禁止单个字符扩展
?!(叹号) - 历史命令替换
bash的配置文件
?按生效范围划分,存在两类:
?全局配置:
/etc/profile
/etc/profile.d/*.sh
/etc/bashrc
?个人配置:
~/.bash_profile
~/.bashrc
bashrc bash run command
source 这种写法在当前脚本中运行
一般配置文件用source
变量普通脚本是不能支持别名的
10:16
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
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 个历史命令
read x y z <<< "i j k"
echo $.
9:42
49
11:34
如何判断命令是否存在?
which mkisofs >& /dev/null
if [ "$?" != 0 ] ; then
echo "mkisofs Not Found"
echo "yum install mkisofs"
fi
判断文件是否存在?
if [ -f $2 ]; then
echo "....."
exit 1
fi
test(选项)
选项
-b<文件>:如果文件为一个块特殊文件,则为真;
-c<文件>:如果文件为一个字符特殊文件,则为真;
-d<文件>:如果文件为一个目录,则为真;
-e<文件>:如果文件存在,则为真;
-f<文件>:如果文件为一个普通文件,则为真;
-g<文件>:如果设置了文件的SGID位,则为真;
-G<文件>:如果文件存在且归该组所有,则为真;
-k<文件>:如果设置了文件的粘着位,则为真;
-O<文件>:如果文件存在并且归该用户所有,则为真;
-p<文件>:如果文件为一个命名管道,则为真;
-r<文件>:如果文件可读,则为真;
-s<文件>:如果文件的长度不为零,则为真;
-S<文件>:如果文件为一个套接字特殊文件,则为真;
-u<文件>:如果设置了文件的SUID位,则为真;
-w<文件>:如果文件可写,则为真;
-x<文件>:如果文件可执行,则为真。
实例
linux中shell编程中的test常见用法:
判断表达式
if test #表达式为真
if test ! #表达式为假
test 表达式1 –a 表达式2 #两个表达式都为真
test 表达式1 –o 表达式2 #两个表达式有一个为真
test 表达式1 ! 表达式2 #条件求反
判断字符串
test –n 字符串 #字符串的长度非零
test –z 字符串 #字符串的长度是否为零
test 字符串1=字符串2 #字符串是否相等,若相等返回true
test 字符串1!=字符串2 #字符串是否不等,若不等反悔false
判断整数
test 整数1 -eq 整数2 #整数相等
test 整数1 -ge 整数2 #整数1大于等于整数2
test 整数1 -gt 整数2 #整数1大于整数2
test 整数1 -le 整数2 #整数1小于等于整数2
test 整数1 -lt 整数2 #整数1小于整数2
test 整数1 -ne 整数2 #整数1不等于整数2
判断文件
test File1 –ef File2 两个文件是否为同一个文件,可用于硬连接。主要判断两个文件是否指向同一个inode。
test File1 –nt File2 判断文件1是否比文件2新
test File1 –ot File2 判断文件1比是否文件2旧
test –b file #文件是否块设备文件
test –c File #文件并且是字符设备文件
test –d File #文件并且是目录
test –e File #文件是否存在 (常用)
test –f File #文件是否为正规文件 (常用)
test –g File #文件是否是设置了组id
test –G File #文件属于的有效组ID
test –h File #文件是否是一个符号链接(同-L)
test –k File #文件是否设置了Sticky bit位
test –b File #文件存在并且是块设备文件
test –L File #文件是否是一个符号链接(同-h)
test –o File #文件的属于有效用户ID
test –p File #文件是一个命名管道
test –r File #文件是否可读
test –s File #文件是否是非空白文件
test –t FD #文件描述符是在一个终端打开的
test –u File #文件存在并且设置了它的set-user-id位
test –w File #文件是否存在并可写
test –x File #文件属否存在并可执行
expr用法
expr命令一般用于整数值,但也可用于字符串。一般格式为:
#expr argument operator argument
expr也是一个手工命令行计数器。
#$expr 10 + 10
20
#$expr 1500 + 900
2500
#$expr 30 / 3
10
#$expr 30 / 3 / 2
5
(注意运算符左右都有空格)
使用乘号时,必须用反斜线屏蔽其特定含义。因为shell可能会误解显示星号的意义。
#$expr 30 * 3
90
17.5.1 增量计数
expr在循环中用于增量计算。首先,循环初始化为0,然后循环值加1,反引号的用法意
即替代命令。最基本的一种是从(expr)命令接受输出并将之放入循环变量。
$LOOP=0
#$LOOP=`expr $LOOP + 1`
17.5.2 数值测试
可以用expr测试一个数。如果试图计算非整数,将返回错误。
$rr=1.1
#$expr $rr + 1
#expr: non-numeric argument
$rr=2
$expr $rr + 1
3
(注意:这个例子与原文不同)
这里需要将一个值赋予变量(不管其内容如何),进行数值运算,并将输出导入dev/null,
然后测试最后命令状态,如果为0,证明这是一个数,其他则表明为非数值。
$value=12
#$expr $value + 10 > /dev/null 2>&1
$echo $?
0
这是一个数。
$value=hello
#$expr $value + 10 > /dev/null 2>&1
$echo $?
2
这是一个非数值字符。
expr也可以返回其本身的退出状态,不幸的是返回值与系统最后退出命令刚好相反,成功返回1,任何其他值为无效或错误。下面的例子测试两个字符串是否相等,这里字符串为“hello”和“hello”。
$value=hello
$expr $value = "hello"
1
$echo $?
0
expr返回1。不要混淆了,这表明成功。现在检验其最后退出状态,返回0表示测试成功,
“hello”确实等于“hello”。
17.5.3 模式匹配
expr也有模式匹配功能。可以使用expr通过指定冒号选项计算字符串中字符数。.*意即任何字符重复0次或多次。
$value=accounts.doc
$expr $value : ‘.*‘
12
在expr中可以使用字符串匹配操作,这里使用模式. d o c抽取文件附属名。
$expr $value : ‘(.*).doc‘
accounts
原文:http://blog.51cto.com/13870640/2177910