1变量
[root@zab ~]# name=zhang
[root@zab ~]# echo $name
zhang
[root@zab ~]# vim zh.sh
#!/bin/bash
echo "$name"
name=wang
echo "zh.sh:name=$name"
~
[root@zab ~]# bash zh.sh
zh.sh:name=wang
[root@zab ~]# echo $name
zhang
[root@zab ~]# source zh.sh = . zh.sh
zh.sh:name=wang
[root@zab ~]# echo $name
wang
程序执行用bash不需要执行权限 。执行需要执行权限以及程序的路径执行。如./zh.sh 在当前目录下执行 /root/zh.sh 绝对路径执行 source会影响操作环境。
bash和.会开启子进程 。source不会开启子进程。.
显示当前进程编号echo $$
显示进程关系 pstree -p
[root@zab ~]# num1=zhang
[root@zab ~]# num2=$num1 ---- 把num1指向的数据地址zhang 让num2也指向地址zhang 并不是num2指向num1
[root@zab ~]# echo $num1
zhang
[root@zab ~]# echo $num2
zhang
[root@zab ~]# num1=wang ---- num1的指向地址由zhang变为wang
[root@zab ~]# echo $num1
wang
[root@zab ~]# echo $num2 ---- num2的指向地址还是zhang
Zhang
[root@zab ~]# unset num1 num2 ----当脚本执行完后,需unset取消变量定义 如果取消环境变量。会影响调用该变量的进程。
2变量种类
*本地变量:生效范围当前shell进程 在脚本下定义变量为本地变量 不能影响脚本里的脚本
[root@zab ~]# vim f1.sh
#!/bin/bash
n="su1"
echo "f1.sh:n=$n"
./f2.sh 调用f2.sh 要指明路径
~
[root@zab ~]# vim f2.sh
#!/bin/bash
echo "f2.sh:n=$n"
s="su2"
echo "f2.sh:s=$s"
~
[root@zab ~]# chmod +x f2.sh 给f2.sh赋予执行权限
[root@zab ~]# bash f1.sh
f1.sh:n=su1
f2.sh:n= 未显示
f2.sh:s=su2
[root@zab ~]# bash -x f1.sh 进行调试
+ n=su1
+ echo f1.sh:n=su1
f1.sh:n=su1
+ ./f2.sh
f2.sh:n= 变量n为本地变量只对f1.sh生效 未对f2.sh生效
f2.sh:s=su2
注意{ ;空格}
在操作环境终端下输入定义name 变量赋值 name变量影响子进程b.sh 以及b.sh脚本中脚本f1.sh
*变量赋值:(1) 可以是直接字串; name="root" (2) 变量引用:name="$USER" (3) 命令引用:name=`COMMAND` name=$(COMMAND)
(2)变量引用:${name} $name
[root@zab ~]# name=`cat /etc/fstab`
[root@zab ~]# echo $name
# # /etc/fstab # Created by anaconda on Tue Jul 11 21:48:40 2017 # # Accessible filesystems, by reference, are maintained under '/dev/disk'
[root@zab ~]# echo "$name"
#
# /etc/fstab
# Created by anaconda on Tue Jul 11 21:48:40 2017
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
"$name" $name两者区别
如果name=命令
要执行命令 $name
3.环境变量:生效范围为当前shell进程以及子进程 脚本下定义环境变量 会影响脚本里脚本
[root@zab ~]# vim f1.sh
#!/bin/bash
n="su1"
export n n为环境变量
echo "f1.sh:n=$n"
./f2.sh 调用f2.sh
echo "f1.sh:n=$n"
[root@zab ~]# vim f2.sh
#!/bin/bash
echo "f2.sh:n=$n"
s="su2"
echo "f2.sh:s=$s"
n="su3" 环境变量n重新赋值su3
echo "f2.sh:n=$n"
./f3.sh
[root@zab ~]# vim f3.sh
#!/bin/bash
echo "f3.sh:n=$n"
[root@zab ~]# chmod +x f3.sh
[root@zab ~]# bash f1.sh
f1.sh:n=su1 定义n为环境变量 值为su1
f2.sh:n=su1 环境变量f2.sh中n为su1
f2.sh:s=su2 f2.sh并给S赋值 并重新定义环境变量n 赋值为su3
f2.sh:n=su3 n值为su3
f3.sh:n=su3 在f2.sh中调用f3.sh 因为环境变量n重新定义su3
f1.sh:n=su1 返回f1.sh中 n的值为su1
可以发现环境变量会影响当前shell进程以及后续的子进程,但不会影响向上的父进程。
变量声明、赋值: export name=VALUE declare -x name=VALUE
变量引用:$name, ${name}
*脚本调试:
检测脚本中的语法错误bash -n *.sh
调试执行 bash -x *.sh
*脚本不能识别别名
只读变量:只能声明,但不能修改和删除 Ü
声明只读变量: readonly name declare -r name Ü
查看只读变量: readonly –p
在脚本中set -- 清空所有位置变量
unset name 取消变量
*只读变量
[root@zab ~]# name=zhang;file=d.log;(age=20;echo $age;echo $name;name=wang;num=two);echo $name;echo $num;echo $file
20
zhang
zhang
d.log
括号内变量只影响括号内 括号外的变量能影响括号内 括号相当于开启子shell进程
[root@zab ~]# umask
0022
[root@zab ~]# (umask 777;touch f1)
[root@zab ~]# ll f1
----------. 1 root root 0 Jul 27 18:24 f1 umask为777
[root@zab ~]# touch f3
[root@zab ~]# ll f3 umask为022
-rw-r--r--. 1 root root 0 Jul 27 18:25 f3 umask在括号内定义,只影响括号内;括号外不影响,umask为原值
*位置变量:在脚本代码中调用通过命令行传递给脚本的参数
$1, $2, ...:对应第1、第2等参数,shift [n]换位置
$0: 命令本身
$*: 传递给脚本的所有参数,全部参数合为一个字符串
$@: 传递给脚本的所有参数,每个参数为独立字符串
$#: 传递给脚本的参数的个数
$@ $* 只在被双引号包起来的时候才会有差异
set -- 清空所有位置变量
[root@zab ~]# vim f1.sh {a..m}
#!/bin/bash
echo "1st arg is $1"
echo "2st arg is $2"
echo "10st arg is ${10}"
echo "All args are $*"
echo "All args are $@"
echo "$0"
echo "$#"
~
[root@zab ~]# bash f1.sh {a..m}
1st arg is a
2st arg is b
10st arg is j
All args are a b c d e f g h i j k l m
All args are a b c d e f g h i j k l m
f1.sh
13
[root@zab ~]# bash f1.sh {a..m}
#!/bin/bash
echo "1st arg is $1"
echo "All args are $@"
shift 2
echo "shift 2"
echo "1st arg is $1"
echo "All args are $@"
~
[root@zab ~]# bash f1.sh {a..m}
1st arg is a
All args are a b c d e f g h i j k l m
shift 2 shift [n]换位置
1st arg is c 第一个参数变为c
All args are c d e f g h i j k l m
[root@zab ~]# vim f2.sh
#!/bin/bash
echo "$@"
./f3.sh "$@" 创建f3.sh 需指明路径
./f4.sh "$*" 同上
[root@zab ~]# vim f3.sh
#!/bin/bash
echo "$1"
[root@zab ~]# vim f4.sh
#!/bin/bash
echo "$1"
[root@zab ~]# chmod +x f3.sh
[root@zab ~]# chmod +x f4.sh
[root@zab ~]# bash f2.sh {a..m}
a b c d e f g h i j k l m
a
a b c d e f g h i j k l m
[root@zab ~]# bash -x f2.sh {a..m}
+ echo a b c d e f g h i j k l m
a b c d e f g h i j k l m
+ ./f3.sh a b c d e f g h i j k l m $@
a $1
+ ./f4.sh 'a b c d e f g h i j k l m' $*
a b c d e f g h i j k l m $1
$*与$@区别
*自动生成脚本前描述信息
[root@zab ~]# vim scipt.sh
#!/bin/bash
cat>$1< #!/bin/bash ###################### #auther:71 #creat-time:`date +%F` #filename:`basename $1` ###################### eof vim + $1 chmod +x $1 ~ ~ [root@zab ~]# bash scipt.sh zab.sh #!/bin/bash ###################### #auther:71 #creat-time:2017-07-27 #filename:zab.sh ###################### ~ ~ 退出状态 进程使用退出状态来报告成功或失败 • 0 代表成功,1-255代表失败 • $? 变量保存最近的命令退出状态 vbash自定义退出状态码 exit [n]:自定义退出状态码 用于编写脚本执行命令,给命令不同的状态码,看命令是否成功 注意:脚本中一旦遇到exit命令,脚本会立即终止;终止退出 状态取决于exit命令后面的数字 注意:如果未给脚本指定退出状态码,整个脚本的退出状态码 取决于脚本中执行的最后一条命令的状态码 exit退出 在字符界面当前终端 在脚本里退出当前进程 [root@centos7 ~]#cat b.sh #!/bin/bash cmd (exit 100) ()号表示开启的子进程 exit退出当前子进程 hostname [root@centos7 ~]#bash b.sh b.sh: line 2: cmd: command not found centos7.64 继续执行 #!/bin/bash cmd exit 100 退出当前进程 hostname 不执行 [root@centos7 ~]#bash b.sh b.sh: line 2: cmd: command not found [root@centos7 ~]#echo $? 100 算术运算 vbash中的算术运算:help let +, -, *, /, %取模(取余), **(乘方) 数字 $[number] 实现算术运算: (1) let var=算术表达式 let c=a+b echo $c (2) var=$[算术表达式] (3) var=$((算术表达式)) $((a-b)) (4) var=$(expr arg1 arg2 arg3 ...) expr 1 + 2 命令 1 + 2为参数 需要空格 expr 0 + $num 可用于判断num是不是非0的整数 5) declare –i var = 数值 (6) echo ‘算术表达式’ | bc v 乘法符号有些场景中需要转义,如* 为(\*) bash有内建的随机数生成器:$RANDOM(0-32767) echo $[$RANDOM%50] :0-49之间随机 echo $SHLVL 当前进程嵌套深度pstree -p 查看 [root@centos7 ~]#i=10 [root@centos7 ~]#let j=i++ [root@centos7 ~]#echo $j 10 [root@centos7 ~]#echo $i 11 [root@centos7 ~]#unset i [root@centos7 ~]#i=10 [root@centos7 ~]#let j=++i [root@centos7 ~]#echo $j 11 [root@centos7 ~]#echo $i 11 注意如下 [root@centos7 ~]#unset k [root@centos7 ~]#let k=0 [root@centos7 ~]#let k++ k为0 [root@centos7 ~]#echo $? 1 [root@centos7 ~]#unset k [root@centos7 ~]#let k=0 [root@centos7 ~]#let ++k k为1 [root@centos7 ~]#echo $? 0 exit状态 最后一个参数为0,将返回1 [root@centos7 ~]#let k+=6 [root@centos7 ~]#echo $k 7 [root@centos7 ~]#let k+=6 = k=k+6 [root@centos7 ~]#echo $k 13 条件测试 用于两个参数进行判断 专用的测试表达式需要由测试命令辅助完成测试过程 • [ EXPRESSION ] •[[ EXPRESSION ]] 用于正则表达式 注意:EXPRESSION前后必须有空白字符 []内是字符串、数值、文件测试 单条命令行判断不需要[]中括号 表达式查看test man帮助 注意如下 [root@centos7 ~]#var=' ' [root@centos7 ~]#[ $var ] && echo true [root@centos7 ~]#echo $? 1 字符为空 判断为假 [root@centos7 ~]#[ 0 ] && echo true true 1.字符串测试
= 等于则为真 变量比较用到的操作数需加引号 [ "$a" = "wang" ] 或者[ x$a == x"wang" ]前面加字符防止$a为空而报错 格式的例子: [ "abc" = "abc" ] && echo "Strings are equal" != 是否不等于,不相等为真 =~ 左侧字符串是否能够被右侧的PATTERN所匹配 注意: 此表达式一般用于[[ ]]中;扩展的正则表达式 [[ $a =~ \<[Yy]|([Yy][Ee][sS])$ ]] && echo "hello" ||echo "fk" -z "STRING“ 字符串是否为空,空为真,不空为假 [ ! -z string ] 等同于 [ -n srting ] -n "STRING“ 字符串是否不空,不空为真,空为假 实例演示: num1="ru1noob" 输出结果: 两个字符串不相等! 2.数值测试 -eq 等于则为真 -le小于等于则为真 -lt小于则为真 -ge大于等于则为真 -gt大于则为真 实例演示: num1=100 输出结果: 两个数相等! 代码中的 [] 执行基本的算数运算,如: #!/bin/bash a=5 result=$[a+b] # 注意等号两边不能有空格 结果为: result 为: 11 Bash的文件权限测试 3.文件测试 文件存在测试: -e 文件名 如果文件存在则为真 -s 文件名 如果文件存在且内容非空则为真
文件类型测试: -d 文件名 如果文件存在且为目录则为真 -f 文件名 如果文件存在且为普通文件则为真 -c 文件名 如果文件存在且为字符型特殊文件则为真
-b 文件名 如果文件存在且为块特殊文件则为真 文件是否打开: -t fd: fd表示文件描述符是否已经打开且与某终端相关 -N FILE:文件自动上一次被读取之后是否被修改过 -O FILE:当前有效用户是否为文件属主 文件所有者 -G FILE:当前有效用户是否为文件属组 文件所属组 文件权限测试: 实际权限 -r FILE:是否存在且可读 -w FILE: 是否存在且可写 -x FILE: 是否存在且可执行 文件特殊权限测试: -u FILE:是否存在且拥有suid权限 -g FILE:是否存在且拥有sgid权限 -k FILE:是否存在且拥有sticky权限 双目测试: FILE1 -ef FILE2: FILE1与FILE2是否指向同一个设 备上的相同inode file1是不是file2硬链接 FILE1 -nt FILE2: FILE1是否新于FILE2(mtime) FILE1 -ot FILE2: FILE1是否旧于FILE 另外,Shell还提供了与( -a )、或( -o )、非( ! )三个逻辑操作符用于将测试条件连接起来,其优先级为:"!"最高,"-a"次之,"-o"最低。 例如: cd /bin 输出结果: 有一个文件存在! 逻辑运算 如果true 1,false 0 与: 1 与 1 = 1 或: 1 或 1 = 1 1 与 0 = 0 1 或 0 = 1 0 与 1 = 0 0 或 1 = 1 0 与 0 = 0 0 或 0 = 0 短路运算 非:! ! 1 = 0 ! 0 = 1 短路与 第一个为0,结果必定为0 第一个为1,第二个必须要参与运算 短路或 第一个为1,结果必定为1 第一个为0,第二个必须要参与运算 条件性的执行操作符 && 代表条件性的AND THEN || 代表条件性的OR ELSE Bash的组合测试条件 第一种方式: COMMAND1 && COMMAND2 并且 COMMAND1 || COMMAND2 或者 ! COMMAND 非 如:[ -r FILE ] && [ -w FILE ] 第二种方式: EXPRESSION1 -a EXPRESSION2 并且 EXPRESSION1 -o EXPRESSION2 或者 ! EXPRESSION 必须使用测试命令进行 EXPRESSION1 -o EXPRESSION2 = COMMAND1 || COMMAND2 EXPRESSION1 -a EXPRESSION2 = COMMAND1 && COMMAND2 [ -r file -a -w file ] 等同于 [ -r FILE ] && [ -w FILE ] ! EXPRESSION EXPRESSION is false [ ! EXPRESSION1 -a EXPRESSION2] = -not expression1 -o -not expression2 [ ! EXPRESSION1 -o EXPRESSION2] = -not expression1 -a -not expression2 EXPRESSION1 -a EXPRESSION2 both EXPRESSION1 and EXPRESSION2 are true EXPRESSION1 -o EXPRESSION2 either EXPRESSION1 or EXPRESSION2 is true 示例: [root@centos7 ~]#num=60 [root@centos7 ~]#[ $num -gt 30 -a $num -lt 100 ] && echo "right"||echo "error" right 等同于 [root@centos6 ~]#[ $num -gt 30 ] && [ $num -lt 100 ] && echo "right" ||echo "error" right cmd1 &&cmd2 ||cmd3 Cmd1 为假 cmd2 不执行 执行cmd3 cmd1为真 cmd2 执行 不执行cmd3 [root@centos7 ~]#id wang; id wang &> /dev/null && echo "id wang exist" || useradd wang #!/bin/bash name=wang; id $name &> /dev/null && { echo "$name exist";exit 100; } ||(useradd wang;echo bing|passwd --stdin $name; ) 判断num是不是整数 [root@centos7 ~]#expr 0 + $num && echo "$num is number" || echo "$num is not number" 只能判断非0整数 [root@centos7 ~]#expr 0 + $num && echo "$num is number" || echo "$num is not number" [root@centos7 ~]#[[ $num =~ ^-?[0-9]+$ ]] && echo "$num is number"|| echo "$num is not number" 使用read命令来接受输入参数变量 v 使用read来把输入值分配给一个或多个shell变量 -p 指定要显示的提示 -s 静默输入,一般用于密码 -n N 指定输入的字符长度N -d ‘字符’ 输入结束符 -t N TIMEOUT为N秒 read 从标准输入中读取值,给每个单词分配一个变量 所有剩余单词都被分配给最后一个变量 read -p “Enter a filename: “ FILE #!/bin/bash read -s -p "please input your passwd: " pass echo -e "\nyour passwd is $pass" 多个变量 防止扩展 v 反斜线(\)会使随后的字符按原意解释 $ echo Your cost: \$5.00 Your cost: $5.00 v 加引号来防止扩展 • 单引号(’)防止所有扩展 • 双引号(”)也防止所有扩展,但是以下情况例外: î $(美元符号) - 变量扩展 î(反引号) - 命令替换 î \(反斜线) - 禁止单个字符扩展 î !(叹号) - 历史命令替换 bash的配置文件 用户登录自动生成bash终端 全局配置: /etc/profile /etc/profile.d/*.sh /etc/bashrc v 个人配置: ~/.bash_profile ~/.bashrc shell登录两种方式 v 交互式登录: (1)直接通过终端输入账号密码登录 (2)使用“su - UserName” 切换的用户 执行顺序:/etc/profile --> /etc/profile.d/*.sh --> ~/.bash_profile --> ~/.bashrc --> /etc/bashrc v 调用 # .bashrc # User specific aliases and functions PS1="\[\e[31m\][\u@\h \W]\\$\[\e[0m\]" alias rm='rm -i' alias cp='cp -i' alias mv='mv -i' #别名定义 # Source global definitions if [ -f /etc/bashrc ]; then . /etc/bashrc fi ~ ~ ~ .bashrc ——>/etc/bashrc ~ ~ 非交互式登录: (1)su UserName (2)图形界面下打开的终端 (3)执行脚本 (4)任何其它的bash实例 执行顺序: ~/.bashrc --> /etc/bashrc --> /etc/profile.d/*.sh 按功能划分,存在两类: profile类和bashrc类 vprofile类:为交互式登录的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 退出任务 v 保存在~/.bash_logout文件中(用户) v 在退出登录shell时运行 v 用于 • 创建自动备份 • 清除临时文件 v1、让所有用户的PATH环境变量的值多出一个路径,例如: /usr/local/apache/bin v2、用户root登录时,将命令指示符变成红色,并自动启用如 下别名:rm=‘rm –i’ cdnet=‘cd /etc/sysconfig/network-scripts/’ editnet=‘vim /etc/sysconfig/network-scripts/ifcfg-eth0’ editnet=‘vim /etc/sysconfig/network-scripts/ifcfgeno16777736 或 ifcfg-ens33 ’ (如果系统是CentOS7) 在 vim .bashrc配置文件中定义 v3、任意用户登录系统时,显示红色字体的警示提醒信息 “Hi,dangerous!” v4、编写生成脚本基本格式的脚本,包括作者,联系方式,版 本,时间,描述等 [root@zab ~]# vim scipt.sh #!/bin/bash cat>$1< #!/bin/bash ###################### #auther:71 #creat-time:`date +%F` #filename:`basename $1` ###################### Eof chmod +x $1 vim + $1
num2="runoob"
if [ $num1 = $num2 ]
then
echo '两个字符串相等!'
else
echo '两个字符串不相等!'
fi
num2=100
if [ ${num1} -eq ${num2} ]
then
echo '两个数相等!'
else
echo '两个数不相等!'
fi
b=6
echo "result 为: $result"
if [ -e ./notFile -o -e ./bash ]
then
echo '有一个文件存在!'
else
echo '两个文件都不存在'
fi