1.bash特性之多命令执行
cmd
cmd1 `cmd2` #引用
cmd1 | cmd2 | cmd3 | ... #管道
逻辑组合:
cmd1 && cmd2 && ... 与
cmd1 || cmd2 || ... 或
!cmd1 非
逻辑运算:
运算数:true,false
返回值:0(true),false(1-255)
与:true && true = truetrue && false = false第一个操作数为true,其结果将取决于第二个操作数;false && true = falsefalse && false = false第一个操作数为False,其结果至此可断定,为false;或:true || true = truetrue || false = true第一个操作数为true,其结果至此可断定,为true;false || true = truefalse || false = false第一个操作数为false,其结果将取决于第二个操作数;非:! true = false! false = true
练习:写一个脚本,实现如何功能;
(1) 用户storm不存在时,添加之;添加完成后,显示添加结果;
(2) 否则,显示其已经存在;
#!/bin/bash
! id $name && useradd $name && echo "the $name has been add"||echo "the user $name has exist"
2.bash的配置文件
程序:定制工作特性(命令行选项、配置文件)
配置文件分三类:
profile类:为交互式登录的shell进程实现初始化的配置文件
bashrc类:为交互式登录的shell进程实现启动配置的配置文件;
logout类:为交互式登录的shell进程提供终止清理功能的配置文件;
根据配置文件的作用范围可分为两类:
全局:对所有用户生效
/etc/profile, /etc/profile.d/*.sh
/etc/bashrc
注意:仅管理员有权限修改;
用户个人:仅对单个用户有效
~/.bash_profile
~/.bashrc
配置文件的作用:
(1) profile类
用于定义环境变量;
用于运行命令或脚本;
(2) bashrc类
用于定义本地变量;
定义命令别名;
定义umask;
shell进程的启动方式有两类:
用户以登录方式启动(登录式shell):
通过终端登录用户启动的shell进程;
使用su -l username或su - username实现的用户切换;
以非登录方式启动(非登录式shell):
su username实现的用户切换;
图形界面下打开的命令行接口;
运行脚本;
登录式shell:
/etc/profile --> /etc/profile.d/*.sh --> ~/.bash_profile --> ~/.bashrc --> /etc/bashrc
非登录式shell:
~/.bashrc --> /etc/bashrc --> /etc/profile.d/*.sh
让配置文件中新定义的配置生效的方式:
(1) 重新启动shell进程;
登出而后登录;
exec /bin/bash
(2) 使用source命令执行指定文件中的代码
source /PATH/TO/SOMEFILE
. /PATH/TO/SOMEFILE
注意:有副作用
3.bash脚本编程之算术运算
算术运行符:
+,-
*, /
%:取余
**:次方
算术运算格式:
(1) let VAR=算术表达式
(2) VAR=$[算术表达式]
(3) VAR=$((算术表达式))
(4) VAR=$(expr $ARG1 $OP $ARG2)
练习:写一个脚本,完成如下功能;
/etc/passwd文件中的root、daemon和shutdown三个用户的id之和;
#!/bin.bash
n1=$(id -u root)
n2=$(id -u daemon)
n3=$(id -u shutdown)
let sum=$n1+$n2+$n3
echo $sum
练习:求/etc/fstab、/etc/grub2.cfg和/etc/issue文件的行数之和;
num1=$(wc -l /etc/fstab|grep -o '^[0-9]*>')
num2=$(wc -l /etc/grub2.cfg|grep -o '^[0-9]*>')
num3=$(wc -l /etc/issue|grep -o '^[0-9]*>')
let num0=$num1+$num2+$num3
echo $num0
#或者
num1=$(cat /etc/fstab | wc -l)
求上述三个文件中的总空白行数;
num1=$(grep '^$' /etc/fstab|wc -l)
num2=$(grep '^$' /etc/grub2.cfg|wc -l)
num3=$(grep '^$' /etc/issue|wc -l)
let num0=$num1+$num2+$num3
echo $num0
4.bash脚本编程格式
脚本文件格式:
数据类型:字符型、数值型第一行,顶格:#!/bin/bash注释信息:#代码注释:缩进,适度添加空白行;
弱类型:字符型
5.bash脚本编程之算术运算
算术运算:+,-,*,/(除),%(求余),**(乘方)
增强型赋值:变量做某种算术运算后回存至此变量中let VAR=expressionVAR=$[expression]VAR=$((expression))VAR=$(expr argu1 argu2 argu3)注意:有些时候乘法符号需要转义;
let i=$i+#,每次自加#
let i+=#
例1:写一个脚本+=,-=,*=, /=, %=自增:VAR=$[$VAR+1]let VAR+=1let VAR++自减:VAR=$[$VAR-1]let VAR-=1let VAR--
计算/etc/passwd文件中的第10个用户和第20个用户的id号之和;
id1=$(head -10 /etc/passwd | tail -1 | cut -d: -f3)
id2=$(head -20 /etc/passwd | tail -1 | cut -d: -f3)
#!/bin/bash
n1=$(head -10 /etc/passwd | tail -1 | cut -d ":" -f3)
n2=$(head -20 /etc/passwd | tail -1 | cut -d ":" -f3)
let sum=$n1+$n2
echo "The sum is $sum."
5.bash脚本编程之条件测试
条件测试:判断某需求是否满足,需要由测试机制来实现
如何编写测试表达式以实现所需的测试:
bash的条件测试:1.执行命令,并利用命令状态返回值来判断0:成功1-255:失败2.测试表达式test expression[ expression ][[ expression ]]注意:expression两端必须有空白字符,否则为语法错误
1.数值测试
2.字符串测试
3.文件测试
5.1 数值测试
数值测试:数值比较
-eq:是否等于,[ $num1 -eq $num2 ]-ne:是否不等于-gt:是否大于-ge:是否大于等于-lt:是否小于-le:是否小于等于
5.2 字符串测试
==:是否等于>:是否大于<:是否小于!=:是否不等于=~:左侧字符串是否能够被右侧的pattern所匹配-z "string":判断指定的字串是否为空;空则为真,不空则假;-n "string":判断指定的字符串是否不空;不空则真,空则为假;注意:(1) 字符串要加引用;(2) 要使用[[ ]];
5.3 文件测试
5.3.1 存在性测试
-a file
-e file
文件的存在性测试,存在则为真,否则为假
5.3.2 存在型及类型测试
-b file:是否存在并为块设备文件
-c file:是否存在且为字符设备文件
-d file:是否存在且为目录文件
-f file:是否存在且为普通文件
-h file或-L file:是否存在且为符号链接文件
-p file:是否存在且为管道文件
-s file:是否存在且为套接字文件
5.3.3 文件权限测试
-r file:是否存在且对当前用户可读
-w file:是否存在且对当前用户可写
-x file:是否存在且对当前用户可执行
-u file:是否存在且对当前用户拥有suid权限
-g file:是否存在且对当前用户拥有sgid权限
-k file:是否存在且对当前用户拥有sticky权限
5.3.4 其他
文件是否有内容
-s file:是否有内容
时间戳:
-N file:文件自从上一次读操作后是否被修改过
从属关系测试:
-O file:当前用户是否为文件的属主
-G file:当前用户是否为文件的属组
5.3.5 双目测试
FILE1 -ef FILE2:file1与file2是否指向同一个文件系统的相同inode的硬链接
file1 -nt file2:file1是否新于file2
file1 -ot file2:file1是否旧于file2
5.3.4 组合测试条件
逻辑运算:
第一种方式:
第二种方式command1 && command2command1 || command2!command例:[ -O file ] && [ -r file ]
expression1 -a expression2expression1 -o expression2!expression例:[ -O file -a -x file]
例:将当前主机名称保存至hostName变量中;
主机名如果为空,或者为localhost.localdomain,则将其设置为www.magedu.com;
#!/bin/bash
- name=$(hostname)
#注意:上面的括号必须有
[ -z "$name" -o "$name" == "localhost.localdomain" -o "$name" == "localhost" ] && hostname www.mageedu.com || echo "the hostname is `hostname`"
#先判断主机名是否为空或者为localhost.localdomain或localhost,如果为真,就设置为www.mageedu.com,后面的表达式不执行;如果为假,则第二个表达式不执行,执行第三个表达式,显示现在的主机名
6.脚本的状态返回值
脚本的状态返回值:默认是脚本中执行的最后一条命令的状态返回值:
自定义状态退出码:
exit [n]:n为自己指定的状态码
注意:shell进程遇到exit时,机会终止,因此,整个脚本执行即为结束
7.向脚本传递参数
7.1 位置参数变量
位置参数变量:myscript.sh argu1 argu2
练习:写一个脚本,通过命令传递两个文本文件路径给脚本,计算其空白行数之和引用方式:$1,$2,...${10},${11},..轮替:shift [n]:位置参数轮替
#!/bin/bash
- #linenum.sh
- n1=$(grep "^$" $1 | wc -l)
n2=$(grep "^$" $2 | wc -l)
let sum=$n1+$n2
echo "Total blank lines is $sum."
#测试
/bin/bash linenum.sh -x /etc/fstab /etc/virc
7.2 特殊变量
$0:脚本文件路径本身
$1:脚本参数的个数
$*:所有参数
$@:所有参数
例:
#!/bin/bash
num1=$(cat /etc/passwd|wc -l)
num2=$(cat /etc/shadow|wc -l)
let sum=$num1+$num2
echo $sum
pwd
echo "the 0 is $0"
echo "the 1 is $1"
echo "the * is $*"
echo "the @ is $@"
执行结果如下:
8.bash脚本编程之用户交互:
用户交互:通过键盘输入数据,从而完成变量赋值操作
read [option] ... [name ...]
-p 'prompt'
-t timeout
#!/bin/bash
#
echo -e "please enter your test:"
read TESTREAD
echo $TESTREAD
#下面是测试结果:
[root@zhangpf test]# /bin/bash -x ceshi.sh
+ echo -e 'please enter your test:'
please enter your test:
+ read TESTREAD
abc
+ echo abc
abc
bash -n /path/to/some_script
检测脚本中的语法错误
bash -x /path/to/some_script
调试执行
例:执行脚本,可以添加用户,并进行设置密码,如果用户名已经存在就进行提示,如果没有此用户就添加
#!/bin/bash
#
- read -p "please enter a username: " name
[ -z "$name" ] && echo "a username is needed." && exit 2
read -p "please enter a passwd for $name ,[passwd]: " password
[ -z "$password" ] && password="password"
if id $name &>/dev/null;then
echo "The user $name exists."
echo "The user id is `id -u $name`"
else
useradd $name
echo "$password" | passwd -stdin $name &>/dev/null
echo "The user $name finished."
fi