编程基础: 程序:指令+数据 程序编程风格: 过程式:以指令为中心,数据服务于指令。 小软件过程,大软件对象。 对象式:以数据为中心,指令服务于数据 shell程序:提供了编程能力,解释执行 shell脚本基础: shell脚本: 包含一些命令或声明,并符合必定格式的文本文件 格式要求:首行shebang机制 #!/bin/bash #!/usr/bin/python #!/usr/bin/perl shell脚本的用途有: 自动化经常使用命令 执行系统化管理和故障排除 建立简单的应用程序 处理文本或文件
建立shell脚本 第一步:使用文本编辑器来建立文本文件 第一行必须包括shell声明序列:#! #!/bin/bash 添加注释 注释以#开头 第二步:运行脚本 给予执行权限,在命令行上指定脚本的绝对或相对路径 直接运行解释器,将脚本做为解释器程序的参数运行 脚本规范: 脚本代码开头约定: 一、第一行通常为调用使用的语言 二、程序名,避免更改文件名为没法找到正确的文件 三、版本号 四、更改后的时间 五、做者相关信息 六、该程序的做用,及注意事项 七、最后是各版本的更新简要说明 脚本的基本结构: 脚本的基本结构 #!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 只能检查语法错误
变量 变量:命名的内存空间 数据存储方式: 字符: 数值:×××,浮点型 变量:变量类型 做用: 一、数据存储格式 二、参与的运算 三、表示的数据范围 类型: 字符 数值:×××、浮点型 加" "能够改变格式 如: echo="name"
变量: 强类型:变量不通过强制转换,它永远是这个数据类型,不容许隐式的类型转 换。通常定义变量时必须制动类型、参与运算必须符合类型要求;调用未声明 变量会产生错误 如 java,c# 弱类型:语言的运行时回隐形作数据类型转换。无须指定类型,默认均为字符型; 参与运算会自动进行隐式类型转换;变量无需事先定义可直接调用 如:bash不支持浮点数,php 能够用数字可是不能放在前面
变量命名法则: 一、不能使程序中的保留字:列如if,for 二、只能使用数字、字母及下划线,且不能以数字开头 三、见名知义 四、统一命名法则:骆峰命名法:把多个首字母大写,小驼峰:第一个首字母大写,
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 +,-,*,%取模(取余),**(乘方) 实现算数运算: 一、let var=算数表达式 二、var=$[算数表达式] 三、var=$((算数表达式)) 四、var=$(expr arg1 arg2 arg3...) 五、declare -i var =数值 六、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