Shell脚本编程

shell脚本编程基础
 
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”
局部变量:只对当前shell有效 ,可使用set查看
环境变量:对当前shell及期子shell都有效,可使用set、env查看
export 本地变量名
export 变量名=值
若修改环境变量的值 ,可直接变量名=值而不再需要加export
 
 
 
位置化变量
echo '$1' is:$1
echo '$2' is:$2
echo '$3' is:$3
echo '$4' is:$4
echo '$0' is:$0
echo '$10' is:${10}
echo '$*' is:$*
echo '$#' is:$#
 
 
特殊变量
?:表示上一条命令的执行成功与否:0为成功,非0为失败
0 :位置化变量中的命令本身
* :位置化变量中的所有参数
@ : 位置化变量中的所有参数
# :位置化变量的个数
$ :显示当前Shell的进程号
 
 
unset A 删除变量
 
 
 
 
变量声明、赋值:
export name=VALUE
declare -x name=VALUE
变量引用:$name, ${name}
显示所有环境变量:
env
printenv
export
declare -x
删除变量:
unset name
 
 
readonly 变量名
declare -r 变量名=值
 
位置化变量
只读变量:只能声明,但不能修改和删除
声明只读变量:
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 $?
 
exit 脚本执行到exit 就退出,当然exit [n] 同时还能退出示指定返回值。
 
echo $[$RANDOM%50+1]
 
 
 
 
UserName=liuchan; id $UserName &> /dev/null && echo "$UserName is already exist" || ( useradd $UserName ;echo "$UserName created" & )
 
test用法 [ ]
 
== 表示字符串是否相同
-eq 表示两个整数是否相等(可以为负,不能为浮点数)
-gt 大于左边的数是否大于右边的数
-ge 大于等于
-lt 小于
-le 小于等于
-ne 不等于
 
-v 变量名 判断一个变量是否被定义
 
字符串比较
 
== 是否相同
!= 或 <> 表示是否不同
~= 左侧字符串是否能够被右侧的PATTERN所匹配
[[ ab =~ a ]]
[[ b > a ]] 表示在默认编码表中的顺序,排后面的是较大的。
<
[[ a < b ]]
 
 
 
-z "String" 判断字符串是否为空,为空时为真
-n "String" 判断字符串是否为非空,为非空时为真
 
实验:编写脚本/root/bin/argsnum.sh,接受一个文件路径作为参数;如果参数个数小于1,则提示用户“至少应该给一个参数”,并立即退出;如果参数个数不小于1,则显示第一个参数所指向的文件中的空白行数
#!/bin/bash
[ $# -eq 0 ] && echo 至少应该给一个参数 && exit 1
grep "^[[:space:]]*$" $1 |wc -l
 
 
 
 
文件判断
 
-a 或 -e filename 判断文件是否存在,若存在则为真
-b 判断文件是否为块设备
-c 判断文件是否为符号设备
-d FILE:是否存在且为目录文件
-f FILE:是否存在且为普通文件
-h FILE 或 -L FILE:存在且为符号链接文件
-p FILE:是否存在且为命名管道文件
-S FILE:是否存在且为套接字文件
 
 
文件权限测试:
-r FILE:是否存在且可读
-w FILE: 是否存在且可写
-x FILE: 是否存在且可执行
文件特殊权限测试:
-u FILE:是否存在且拥有suid权限
-g FILE:是否存在且拥有sgid权限
-k FILE:是否存在且拥有sticky权限
 
文件大小测试:
-s FILE: 是否存在且非空
文件是否打开:
-t fd: fd 文件描述符是否在某终端已经打开
-N FILE:文件自从上一次被读取之后是否被修改过
-O FILE:当前有效用户是否为文件属主
-G FILE:当前有效用户是否为文件属组
 
双目测试:
FILE1 -ef FILE2: FILE1是否是FILE2的硬链接
FILE1 -nt FILE2: FILE1是否新于FILE2(mtime)
FILE1 -ot FILE2: FILE1是否旧于FILE2
 
多条件判断
方法一:
[liubei@instructor_v7(nanyibo) ~]$ [ -r /app/passwd ] || [ -w /app/passwd ] && echo true
[liubei@instructor_v7(nanyibo) ~]$ [ -r /app/passwd ] && [ -w /app/passwd ] && echo true
 
方法二:
[liubei@instructor_v7(nanyibo) ~]$ [ -r /app/passwd -a -w /app/passwd ] && echo true
[liubei@instructor_v7(nanyibo) ~]$ [ -r /app/passwd -o -w /app/passwd ] && echo true
 
[liubei@instructor_v7(nanyibo) ~]$ [ ! -e /etc/passwda ] && echo true
true
 
 
 
 
 
实验:写一个创建用户的脚本,会询问用户用户名及密码,要求密码输入过程不可见
方法一:
#!/bin/bash
read -p "Please Enter your username: " name
echo -n "Please Enter the password for $name: "
stty -echo
read password
stty echo
echo
useradd $name
echo $password |passwd --stdin $name &> /dev/null
echo "$name created"
 
方法二:
#!/bin/bash
read -p "Please Enter your username: " name
read -sp "Please Enter the password for $name: " password
echo
useradd $name
echo $password |passwd --stdin $name &> /dev/null
echo "$name created"
 
 
转译
\ 完全单个转译
'' 完全范围转译
"" 不完全范围转译对于以下四个符号不可转译
不能去! \ $ `
A="my hostname is $(hostname)"
[root@instructor_v7(nanyibo) app]# echo $A
my hostname is instructor.magedu.com
 
 
 
登录式shell 与 非登录式shell
 
登录式shell
登录图型化
登录文本tty终端
远程登录如ssh,telnet
su -
 
执行顺序:/etc/profile --> /etc/profile.d/*.sh --> ~/.bash_profile --> ~/.bashrc --> /etc/bashrc
 
非登录式
su
执行shell脚本
在已登录的图型介面打开终端
 
 
执行顺序:
~/.bashrc --> /etc/bashrc --> /etc/profile.d/*.sh
 
source 和 . 在当前shell下执行来自文件的命令。
使用脚本执行 是在子shell下执行命令,那么父shell是无法继承来自脚本中的变量
 
 
 
 
 
# Description:
 
 
 
文件查找
locate 基于数据库查找
更新方式 updatedb
数据库位置 /var/lib/mlocate/mlocate.db
 
locate KEYWORD
有用的选项
-i 不区分大小写的搜索
-n N 只列举前N个匹配项目
-r 使用正则表达式
 
示例
搜索名称或路径中带有“conf”的文件
locate conf
使用Regex来搜索以“.conf”结尾的文件
locate -r ‘\.conf$’
 
find
 
find -mindepth 2 -maxdepth 2 -name passwd
./2/passwd
正则搜索文件
 
 
[root@instructor_v7(nanyibo) app]# find /app -regextype posix-extended -regex '/app/.(r..t)...\1er'
/app/aroot123rooter
[root@instructor_v7(nanyibo) app]# find -regextype posix-extended -regex './.(r..t)...\1er'
./aroot123rooter
 
 
df -i in
read -s 静默输入
 
lscpu命令 :查看cpu的详细信息
free:查看内存信息
cat /proc/meminfo :查看内存信息
unsit:删除变量
$$:查看当前进程
pstree -p 查看进程
name=
set :查看变量 set|grep PS1,PS1:是命令提示符,改颜色
echo $_ :调用上一次参数的变量
!$:上一条命令的最后一个参数的调用
 
 
[root@feng ~]# name=test;(echo $name)
test
[root@feng ~]# name=test;(echo $name; name=222;echo $name);echo $name
test
222
test
 
 
scp +脚本名+IP地址 :直接将脚本考到其他IP地址中
 
 
#!/bin/bash
name=etc`date +%F`
cp -a /etc/ /root/$name
 
cp -a /etc/ /root/etc$(date "+%Y-%m-%d")
 
#!/bin/bash
scp $* wang@172.18.1.124
 
直接:bash scp.sh scp.sh
 
 
 
加颜色 颜色是31 到37
1 [root@feng bin]# echo -e "\033[31mred color\033[0m"
red color
红色
 
2 如果是个变量就可以用{}引起来
[root@feng bin]# color=32;echo -e "\033[${color}mred color\033[0
m" red color 绿色
3: 颜色随机
方法1 color=$[RANDOM%7+31];echo -e "\033[${color}mredcolor\033[0m"
方法2 color=`seq 31 37 |sort -R |head -1 `;echo -e "\033[${color}mred color\033[0m"
color=`seq 31 37 |sort -R |head -1 `;echo -e "\033[1;5;${color}mred color\033[0m" 1:高亮 5闪烁
短路与:就是跳过不执行了
||短路或
&&短路与
 
 
cmd1 || cmd2
cmd1为真则cmd2不执行
cmd1为假则执行cmd2
 
1=真,0=假
 
0 || 1 = 1
0 || 0 = 0
1 || 1 = 1
1 || 0 = 1
 
cmd1 && cmd2
cmd1为真则执行cmd2
cmd1为假则不执行cmd2
 
0 && 1 = 0
0 && 0 = 0
1 && 1 = 1
1 && 0 = 0
 
 
/dev/null 空。就是把不想要的东西都放里面,、
id wangxx &> /dev/nu
$?:判断是否为0 若为0就是为真 为假就是非0
 
例子:拼一个主机 ping 172.18.0.1 -w1 -c1 &> /dev/null && echo the hoso
st is up ||echo the host is down 如果拼出来就是打印up ,如果拼不出来就打印down
-c1 :ping 一次
&> :不显示出来
-w1 :1秒
 
/tmp :临时文件夹,相当于回收站
 
 
除数 \ 被除数 = 商
商 *除数 =被除数
被除数 *商 =除数
 
C=A+B
 
A=1
B=0
C=1
 
A=1
B=1
A=0
A
a=6;b=8;a=$[a^b];b=$[a^b];a=$[a^b];echo $a;echo $b
expr :计算输出结果,比如
expr 1+2
y=10;expr $y +0
10
 
 
[root@feng ~]# i=10
[root@feng ~]# j=-10
[root@feng ~]# let sum=i+j
[root@feng ~]# echo $?
1 为假
[root@feng ~]# echo $sum
0
 
test
 
 
[ "变量" ] :判断变量是否存在
 
[ "变量" ] && ls 判断变量是否存在,存在则执行ls,不存在则不执行ls
 
[ "变量" ] || ls 判断变量是否存在,存在则不执行ls,不存在则执行ls
 
 
 
 
局部变量:只对当前shell有效 ,可使用set查看
环境变量:对当前shell及期子shell都有效,可使用set、env查看
export 本地变量名
export 变量名=值
若修改环境变量的值 ,可直接变量名=值而不再需要加export
 
 
 
位置化变量
echo '$1' is:$1
echo '$2' is:$2
echo '$3' is:$3
echo '$4' is:$4
echo '$0' is:$0
echo '$10' is:${10}
echo '$*' is:$*
echo '$#' is:$#
 
 
特殊变量
?:表示上一条命令的执行成功与否:0为成功,非0为失败
0 :位置化变量中的命令本身
* :位置化变量中的所有参数
@ : 位置化变量中的所有参数
# :位置化变量的个数
$ :显示当前Shell的进程号
 
 
unset A 删除变量
 
 
 
 
变量声明、赋值:
export name=VALUE
declare -x name=VALUE
变量引用:$name, ${name}
显示所有环境变量:
env
printenv
export
declare -x
删除变量:
unset name
 
 
readonly 变量名
declare -r 变量名=值
 
位置化变量
只读变量:只能声明,但不能修改和删除
声明只读变量:
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 $?
 
exit 脚本执行到exit 就退出,当然exit [n] 同时还能退出示指定返回值。
 
echo $[$RANDOM%50+1]
 
 
 
 
UserName=liuchan; id $UserName &> /dev/null && echo "$UserName is already exist" || ( useradd $UserName ;echo "$UserName created" & )
 
test用法 [ ]
 
== 表示字符串是否相同
-eq 表示两个整数是否相等(可以为负,不能为浮点数)
-gt 大于左边的数是否大于右边的数
-ge 大于等于
-lt 小于
-le 小于等于
-ne 不等于
 
-v 变量名 判断一个变量是否被定义
 
字符串比较
 
== 是否相同
!= 或 <> 表示是否不同
~= 左侧字符串是否能够被右侧的PATTERN所匹配
[[ ab =~ a ]]
>
[[ b > a ]] 表示在默认编码表中的顺序,排后面的是较大的。
<
[[ a < b ]]
 
 
 
-z "String" 判断字符串是否为空,为空时为真
-n "String" 判断字符串是否为非空,为非空时为真
 
实验:编写脚本/root/bin/argsnum.sh,接受一个文件路径作为参数;如果参数个数小于1,则提示用户“至少应该给一个参数”,并立即退出;如果参数个数不小于1,则显示第一个参数所指向的文件中的空白行数
#!/bin/bash
[ $# -eq 0 ] && echo 至少应该给一个参数 && exit 1
grep "^[[:space:]]*$" $1 |wc -l
 
 
 
 
文件判断
 
-a 或 -e filename 判断文件是否存在,若存在则为真
-b 判断文件是否为块设备
-c 判断文件是否为符号设备
-d FILE:是否存在且为目录文件
-f FILE:是否存在且为普通文件
-h FILE 或 -L FILE:存在且为符号链接文件
-p FILE:是否存在且为命名管道文件
-S FILE:是否存在且为套接字文件
 
 
文件权限测试:
-r FILE:是否存在且可读
-w FILE: 是否存在且可写
-x FILE: 是否存在且可执行
文件特殊权限测试:
-u FILE:是否存在且拥有suid权限
-g FILE:是否存在且拥有sgid权限
-k FILE:是否存在且拥有sticky权限
 
文件大小测试:
-s FILE: 是否存在且非空
文件是否打开:
-t fd: fd 文件描述符是否在某终端已经打开
-N FILE:文件自从上一次被读取之后是否被修改过
-O FILE:当前有效用户是否为文件属主
-G FILE:当前有效用户是否为文件属组
 
双目测试:
FILE1 -ef FILE2: FILE1是否是FILE2的硬链接
FILE1 -nt FILE2: FILE1是否新于FILE2(mtime)
FILE1 -ot FILE2: FILE1是否旧于FILE2
 
多条件判断
方法一:
[liubei@instructor_v7(nanyibo) ~]$ [ -r /app/passwd ] || [ -w /app/passwd ] && echo true
[liubei@instructor_v7(nanyibo) ~]$ [ -r /app/passwd ] && [ -w /app/passwd ] && echo true
 
方法二:
[liubei@instructor_v7(nanyibo) ~]$ [ -r /app/passwd -a -w /app/passwd ] && echo true
[liubei@instructor_v7(nanyibo) ~]$ [ -r /app/passwd -o -w /app/passwd ] && echo true
 
[liubei@instructor_v7(nanyibo) ~]$ [ ! -e /etc/passwda ] && echo true
true
 
 
 
 
 
实验:写一个创建用户的脚本,会询问用户用户名及密码,要求密码输入过程不可见
方法一:
#!/bin/bash
read -p "Please Enter your username: " name
echo -n "Please Enter the password for $name: "
stty -echo
read password
stty echo
echo
useradd $name
echo $password |passwd --stdin $name &> /dev/null
echo "$name created"
 
方法二:
#!/bin/bash
read -p "Please Enter your username: " name
read -sp "Please Enter the password for $name: " password
echo
useradd $name
echo $password |passwd --stdin $name &> /dev/null
echo "$name created"
 
 
转译
\ 完全单个转译
'' 完全范围转译
"" 不完全范围转译对于以下四个符号不可转译
不能去! \ $ `
A="my hostname is $(hostname)"
[root@instructor_v7(nanyibo) app]# echo $A
my hostname is instructor.magedu.com
 
 
 
登录式shell 与 非登录式shell
 
登录式shell
登录图型化
登录文本tty终端
远程登录如ssh,telnet
su -
 
执行顺序:/etc/profile --> /etc/profile.d/*.sh --> ~/.bash_profile --> ~/.bashrc --> /etc/bashrc
 
非登录式
su
执行shell脚本
在已登录的图型介面打开终端
 
 
执行顺序:
~/.bashrc --> /etc/bashrc --> /etc/profile.d/*.sh
 
source 和 . 在当前shell下执行来自文件的命令。
使用脚本执行 是在子shell下执行命令,那么父shell是无法继承来自脚本中的变量
1:高亮 5闪烁
短路与:就是跳过不执行了
||短路或
&&短路与
 
 
cmd1 || cmd2
cmd1为真则cmd2不执行
cmd1为假则执行cmd2
 
1=真,0=假
 
0 || 1 = 1
0 || 0 = 0
1 || 1 = 1
1 || 0 = 1
 
cmd1 && cmd2
cmd1为真则执行cmd2
cmd1为假则不执行cmd2
 
0 && 1 = 0
0 && 0 = 0
1 && 1 = 1
1 && 0 = 0
 
 
/dev/null 空。就是把不想要的东西都放里面,、
id wangxx &> /dev/nu
$?:判断是否为0 若为0就是为真 为假就是非0
 
例子:拼一个主机 ping 172.18.0.1 -w1 -c1 &> /dev/null && echo the hoso
st is up ||echo the host is down 如果拼出来就是打印up ,如果拼不出来就打印down
-c1 :ping 一次
&> :不显示出来
-w1 :1秒
 
/tmp :临时文件夹,相当于回收站
 
 
除数 \ 被除数 = 商
商 *除数 =被除数
被除数 *商 =除数
 
C=A+B
 
A=1
B=0
C=1
 
A=1
B=1
A=0
A
a=6;b=8;a=$[a^b];b=$[a^b];a=$[a^b];echo $a;echo $b
expr :计算输出结果,比如
expr 1+2
y=10;expr $y +0
10
 
 
[root@feng ~]# i=10
[root@feng ~]# j=-10
[root@feng ~]# let sum=i+j
[root@feng ~]# echo $?
1 为假
[root@feng ~]# echo $sum
0
 
test
 
 
[ "变量" ] :判断变量是否存在
 
[ "变量" ] && ls 判断变量是否存在,存在则执行ls,不存在则不执行ls
 
[ "变量" ] || ls 判断变量是否存在,存在则不执行ls,不存在则执行ls
 
 
 
find /etc/ -mm 一分钟之内该过的文件
find -perm -666 -1s 所有着 所属组 其他 都必须要有的权限
find -perm -666 -1s 所有着 所属组 其他 或者的关系
find -perm 666 -1s 精确匹配
如果有/或- 的时候 转换后的二进制的0不检查 - 表示交集 / 表示并集
 
 
 
 
posted @ 2018-07-14 10:45  好名字1995  阅读(204)  评论(0编辑  收藏  举报