shell及编程实例
1.shell简介
1) 概念--命令解释器
2) 常见shell
bash linux标准shell
sh 早期shell,较简单
csh ksh tcsh unix shell
vi /etc/shells linux支持的shell
3) shell脚本--和php一样是脚本语言 所见即所得 在执行过程中进行编译
所有的命令在shell当中都可以直接运行 其他语言比不了
是用来进行系统管理的---写不出漂亮的界面
#!/bin/bash 所有的shell语言都必须以这个开头
# 意思不是注释 而是所有的内容都要调用bash来解释 不可省略 可嵌入其他语言
为了能够让bash知道我要解释的是呢一段内容
例1:打印时间
#!/bin/bash
test=`date +%F` 或 test=$(date +%F) 把目录的结果赋给变量test
echo "today is $test" shell是只需要在调用的时候给变量加上$
[root@CentOS6 sh]# vi hell.sh------------一般写的时候以.sh结尾 系统会加上颜色
[root@CentOS6 sh]#
脚本执行方式:
[root@CentOS6 sh]# ll
总用量 4
-rw-r--r-- 1 root root 39 7月 6 07:07 hell.sh
[root@CentOS6 sh]# chmod 755 hell.sh-----赋予执行权限
[root@CentOS6 sh]# ll
总用量 4
-rwxr-xr-x 1 root root 39 7月 6 07:07 hell.sh
[root@CentOS6 sh]#
A) 赋予执行权限
路径执行-相对路径或者绝对路径的方式来调用它----------一般用此种方式
[root@CentOS6 sh]# /home/sh/hell.sh 绝对路径
2014-07-06
[root@CentOS6 sh]# ./hell.sh 相对路径
2014-07-06
[root@CentOS6 sh]#
B) bash 脚本文件名 此种方式脚本文件可以不赋予执行权限
[root@CentOS6 sh]# /bin/bash hell.sh
2014-07-06
[root@CentOS6 sh]#
4) bash常见功能 掌握
A)历史命令
默认保存1000条历史命令 上下翻 默认保存数可以改
环境变量配置文件总共有四个 下面是第一个
vi /etc/profile 修改环境变量配置文件,要生效,必须注销
HISTSIZE=1000 修改默认历史命令条数
每个用户敲的命令都保存在自己的家目录当中
[root@CentOS6 sh]# cd /
[root@CentOS6 /]# cd
[root@CentOS6 ~]# pwd
/root
[root@CentOS6 ~]# ls -a
.bash_history 保存的是上次登录之前 历史命令保存文件
[root@CentOS6 ~]#
history 查询系统历史命令
历史命令保存文件
~/.bash_history
history -w 把内存中命令历史,保存入.bash_history 文件
history -c 清空所有的历史命令
重复历史命令
!n(命令号) 重复第n条命令
!Str(命令) 重复最后一个以str开头的命令
上箭头↑ 调用上面的命令
B)自动补全
tab 可以进行命令补全(按照PATH路径),也可以进行目录和文件名补全
C)别名
alias 查看系统中生效的别名
alias ls='ls --color=never' 手工设定别名,临时生效
vi ~/.bashrc 写入别名,永久生效(写入环境变量配置文件)
5) 输入输出重定向
标准输入 /dev/stdin 0 键盘
标准输出 /dev/stdout 1 显示器
标准错误输出 /dev/stderr 2 显示器
#设备文件名 #文件描述符 #默认设备
a)输出重定向
把应该输出到屏幕的输出,重定向到文件。
ls > aa 覆盖到aa
ls >> aa 追加到aa
掌握
ls >> aa 2>&1 错误和正确都输入到aa,可以追加
2>&1 把标准错误重定向到标准正确输出
ls >> aa 2>>bb 正确信息输入aa,错误信息输入bb
注意:错误输出的大于号,左右两侧不能有空格
b)输入重定向 了解
[root@CentOS6 ~]# wc
vds
vdsjd
vdsn
3行 3单词 15字符
[root@CentOS6 ~]#
Ctrl + d 保存 单词是按照空格分开的
wc < aa 输入重定向,把文件作为命令的输入
wc << test 后面跟标识符,直到再碰到相同的标志,两个标志之间内容作为命令输入
......
test
[root@CentOS6 ~]# wc < a
17 19 201
[root@CentOS6 ~]# wc a
17 19 201 a
[root@CentOS6 ~]# wc << bbb
> ds
> ds
> fsd
> bbb 这个不算 之间的
3 3 10
[root@CentOS6 ~]#
6) 多命令顺序执行
a)命令1 ; 命令2 ; 命令3 命令123顺序执行。之间没有任何关系
不管命令1正确与否 后面的命令2和3 都会执行
b)命令1 && 命令2 命令1正确执行后,命令2才会执行
逻辑&与
c)命令1 || 命令2 命令1执行不正确,命令2才会执行
ls aa && echo "cunzai" || echo "bu cunzai!" 执行ls aa,判断如果正确,输出“存在”。如果不存在,输出“不存在”
看一下 开始执行时间 和 执行结束时间 复制磁盘a到磁盘b
[root@CentOS6 ~]# ls && echo yes ls正确执行了输出yes
a chongge httpd-2.2.9.gz install.log.syslog 公共的 视频 文档 音乐
anaconda-ks.cfg httpd-2.2.9 install.log stop 模板 图片 下载 桌面
yes
[root@CentOS6 ~]# ls || echo no
a chongge httpd-2.2.9.gz install.log.syslog 公共的 视频 文档 音乐
anaconda-ks.cfg httpd-2.2.9 install.log stop 模板 图片 下载 桌面
[root@CentOS6 ~]# ls cd || echo no ls不正确输出了输出no
ls: 无法访问cd: 没有那个文件或目录
no
[root@CentOS6 ~]#
[root@CentOS6 ~]# ls && echo yes || echo no ls正确输出了输出yes
做一个简单的判断 取代但分支if
a chongge httpd-2.2.9.gz install.log.syslog 公共的 视频 文档 音乐
anaconda-ks.cfg httpd-2.2.9 install.log stop 模板 图片 下载 桌面
yes
[root@CentOS6 ~]# lscds && echo yes || echo no ls和echo yes都不正确执行了输出no
-bash: lscds: command not found
no
[root@CentOS6 ~]#
[root@CentOS6 ~]# lscds || echo no && echo yes
逻辑关系是混乱的 不可以这样写
Lscds执行错误 echo no
Lscds 和 echo no 只要有一个正确执行 就echo yes 这里echo no正确执行
-bash: lscds: command not found
no
yes
[root@CentOS6 ~]#
7) 管道符
命令1 | 命令2 命令1的执行结果,作为命令2的执行条件
Netstat -an
tcp 0 0 192.168.1.107:57050 117.104.138.26:80 ESTABLISHED -------正在连接我的ip
netstat -an | grep ESTABLISHED | wc -l 统计正在连接的网络连接数量
[root@CentOS6 ~]# netstat -an | grep ESTABLISHED | wc -l 显示有多少个人正在连接我
1
[root@CentOS6 ~]#
more 文件名 | grep “字串” 提取含有字符串的行
ls | more 分屏显示ls内容
2. 变量 shel编程了解
1)分类
本地变量(只在一个shell中生效)
环境变量(所有的shell中生效---定义操作环境的)
位置参数变量(预定义变量的一种)
预定义变量(系统事先设定好的)
Pstree---进程树
Set-------查看所有变量
2)本地变量
a)声明 变量名=变量值 注意:=号左右不能有空格
aa=123
b)调用
echo $变量名
c)查看变量
set 查看所有变量,包括环境变量和本地变量
d)删除
unset 变量名
3)变量设定规则
a)变量以等号连接值,等号不能有空格
b)变量名由数字和字母和下划线组成,不能以数字开头
c)变量值中有空格,用引号括起来
d)双引号内,有特殊字符。如$
e)单引号中特殊字符无含义
f)在变量值中,可以使用\转义符
g)变量值可以直接调用系统命令。 `命令` 变量名=$(命令)
如果命令放在等号右边赋给一个变量 此命令需要加上括号或者``
如果命令直接放在shell脚本中执行 不需要加上括号或者``
h)变量值可以累加 aa=123 aa="$aa"456 echo $aa --->123456
[root@CentOS6 ~]# aa=123
[root@CentOS6 ~]# echo $aa
123
[root@CentOS6 ~]# aa="$aa"456
[root@CentOS6 ~]# echo $aa
123456
[root@CentOS6 ~]#
i)环境变量一定设为大写
4)环境变量 ---------最重要的作用是修改系统的默认环境变量
a)声明
export 变量名=变量值
export aa (如果手工不指定类型 变量默认都是字符串类型)declare -x
[root@CentOS6 ~]# echo $aa
123456
[root@CentOS6 ~]# echo $bb
456
[root@CentOS6 ~]# cc=$aa+$bb
[root@CentOS6 ~]# echo $cc
123456+456 -----字符串类型
[root@CentOS6 ~]#
b)查看
set 查看所有变量
env export 只能查看环境变量
declare 声明变量类型的,如果不特别声明,所有变量为字符串型
-i 声明为int
-x 声明为环境变量
c)删除
unset 变量名
d)常见环境变量
PATH=/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
系统查找命令的路径
所有系统预定义的环境变量 例如ls 和 tab键补全 都是在这个路径下去寻找
如果没有就会提示没有
[root@CentOS6 home]# PATH="$PATH":/home/sh
[root@CentOS6 home]# echo $PATH
/usr/lib/qt-3.3/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin:/home/s h
[root@CentOS6 home]# cd sh
[root@CentOS6 sh]# ls
hell.sh
[root@CentOS6 sh]# hell.sh ------改变环境变量中的路径 就可以直接调用环境变量 hell.sh
2014-07-07
[root@CentOS6 sh]#
PATH="$PATH":/root/shell 在系统默认路径后,追加/root/shell目录作为命令查找路径
② PS1=‘[\u@\h \W]\$’ 系统提示符
\u 登录用户名 \h 主机名 \W 最后一个目录 \w 完整所在目录
\T 当前时间 12时 \t 24小时 \# 历史命令条数 \$ 提示符
e)环境变量配置文件
/etc/rc.local 在登陆之前就读取了
/etc/profile etc下的配置文件对所有用户生效 输入用户名密码后生效
/etc/bashrc etc下的配置文件对所有用户生效 输入用户名密码后生效
~/.bashrc 家目录下的只对指定用户生效 输入用户名密码后生效
~/.bash_profile 家目录下的只对指定用户生效 输入用户名密码后生效
再读~/.bash_profile 中.的作用source 环境变量文件名 让配置文件不重启就生效
有完整登陆流程时,加载环境变量顺序-----每次登陆的时候去读取
先读/etc/profile
再读~/.bash_profile
再读~/.bashrc
再读/etc/bashrc
开始Bash界面
3. 位置参数变量
$0 命令自己
$1 第一个参数
$2 第二参数
$9 第九个参数
[root@CentOS6 sh]# vi canshu.sh
[root@CentOS6 sh]# chmod 755 canshu.sh
[root@CentOS6 sh]# ls
canshu.sh
[root@CentOS6 sh]# ll
总用量 4
-rwxr-xr-x 1 root root 74 7月 7 01:36 canshu.sh
[root@CentOS6 sh]# ./canshu.sh(第一参数用户自身) 11(第二参数) 22 33(第N个参数)
mingling is :./canshu.sh
canshu is 11
22
33
[root@CentOS6 sh]#
例2:输出位置参数变量,脚本后要接参数
#!/bin/bash
echo "the command is $0"
echo "canshu1 is $1"
echo "canshu2 is $2"
4. 预定义变量
$? 上一个命令的返回值。 0 上一个命令正确执行 非0 上一个命令不 正确
[root@CentOS6 sh]# echo $?
0
[root@CentOS6 sh]# ls dsdad
ls: 无法访问dsdad: 没有那个文件或目录
[root@CentOS6 sh]# echo $?
2
[root@CentOS6 sh]#
$# 统计命令之后的参数个数
$* 返回所有参数
#!/bin/bash
echo " mingling is :$0"
echo "canshu is $1"
echo $2
echo $3
echo "参数的个数是 $#"
echo "所有参数为 $*"
[root@CentOS6 sh]# vi canshu.sh
[root@CentOS6 sh]# ./canshu.sh 11 22 33 44 55 66
mingling is :./canshu.sh
canshu is 11
22
33
参数的个数是 6
所有参数为 11 22 33 44 55 66
[root@CentOS6 sh]#
$n 位置参数变量
例3:输出预定义变量
#!/bin/bash
echo "canshu zongshu $#"
echo "canshu libiao: $*"
echo $?
5. 键盘读取命令
例2:输出位置参数变量,脚本后要接参数
#!/bin/bash
echo "the command is $0"
echo "canshu1 is $1"
echo "canshu2 is $2"
如果要向程序中传值 推荐使用[root@CentOS6 sh]# vi read.sh
[root@CentOS6 sh]# vi read.sh
[root@CentOS6 sh]# chmod 755 read.sh
[root@CentOS6 sh]# ./read.sh
please input a filename:abcdef
abcdef
[root@CentOS6 sh]#
read -p “提示信息” -t 等待时间 变量名
例子4:通过read读入变量值
#!/bin/bash
read -p "please input num1:" -t 30 test1
read -p "input num2:" -t 30 test2
declare -i sum=$test1+$test2
echo “num1 + num2 = $sum”
[root@CentOS6 sh]# vi read1.sh
[root@CentOS6 sh]# chmod 755 read1.sh
[root@CentOS6 sh]# ./read1.sh
./read1.sh: line 1: !#/bin/bash: 没有那个文件或目录
please input num1:11
input num2:22
sum is 33
[root@CentOS6 sh]# vi read1.sh
[root@CentOS6 sh]#
6. 数值运算
变量值默认都是字符串型,要想进行数值运算。以下三种任选一种
1)declare
num1=123
num2=456
declare -i sum=$num1+$num2
2)sum=$(( $num1 + $num2 ))
3)sum=`expr $num1 + $num2` 注意+左右必须空格
4)运算符
+ - \* / %取余 ----乘号要加转义符
[root@CentOS6 ~]# declare -i cc=$aa+$bb eclare -i cc把变量cc变为整型
[root@CentOS6 ~]# echo $cc
123912
[root@CentOS6 ~]#
[root@CentOS6 ~]# dd=$(($aa+$cc))-----$(()) 也可以转化为整型
此种方法常见!!!!!!!!!!!!!!!!!
[root@CentOS6 ~]# echo $dd
247368
[root@CentOS6 ~]#
root@CentOS6 ~]# ee=`expr $bb+$cc`---------
空格必须有 ` expr 变1 + 变量2 `---------------也可以进行数值运算
[root@CentOS6 ~]# echo $ee
456+123912
[root@CentOS6 ~]# ee=`expr $bb + $cc`-------空格必须有
[root@CentOS6 ~]# echo $ee
124368
[root@CentOS6 ~]#
例5:数据备份
#!/bin/bash
DAY=`date +%Y%m%d`
#定义日期变量
[root@CentOS6 sh]# DAY=`date +%Y%m%d`
[root@CentOS6 sh]# echo $DAY
20140707
[root@CentOS6 sh]#
SIZE=`du -sh /var/lib/mysql`
#定义mysql目录大小的变量
[root@CentOS6 sh]# SIZE=`du -sh /var/lib/mysql`
[root@CentOS6 sh]# echo $SIZE
1.3M /var/lib/mysql
[root@CentOS6 sh]#
echo "Date: $DAY" >> /tmp/dbinfo.txt
#把日期输入信息文档
[root@CentOS6 sh]# echo "Date: $DAY" >> /tmp/dbinfo.txt
[root@CentOS6 sh]# cat /tmp/dbinfo.txt
Date: 20140707
[root@CentOS6 sh]#
echo "Data Size: $SIZE" >> /tmp/dbinfo.txt
#把大小输入信息文档
[root@CentOS6 sh]# echo "Data Size: $SIZE" >> /tmp/dbinfo.txt
[root@CentOS6 sh]# cat /tmp/dbinfo.txt
Date: 20140707
Data Size: 1.3M /var/lib/mysql
[root@CentOS6 sh]#
cd /opt/dbbak
#切换目录备份
tar zcvf mysqlbak-${DAY}.tar.gz /var/lib/mysql /tmp/dbinfo.txt 把数据库和信息文档同时打包
打包备份mysql目录,同时打包信息文档
[root@CentOS6 sh]# tar zcvf mysqlbak-${DAY}.tar.gz /var/lib/mysql /tmp/dbinfo.txt
tar: 从成员名中删除开头的“/”
...............
[root@CentOS6 mysql]# cat /tmp/dbinfo.txt
Date: 20140707
Data Size: 1.3M /var/lib/mysql
[root@CentOS6 mysql]# cd /root/sh
[root@CentOS6 sh]# ls
canshu.sh mysqlbak-20140707.tar.gz read1.sh read.sh
[root@CentOS6 sh]#
rm -f /tmp/dbinfo.txt删除信息文档(打包里面已经有了)
[root@CentOS6 sh]# rm -f /tmp/dbinfo.txt
[root@CentOS6 sh]# cat /tmp/dbinfo.txt
cat: /tmp/dbinfo.txt: 没有那个文件或目录
[root@CentOS6 sh]#
注: cat -A 文件名 显示文件隐,包括藏字符
取消dos文档的回车符,两种办法
1) dos2unix 文档名
2) vi -b 文档
:%s/^M//g ^M使用 ctrl+v+m 输入
etc数据备份
#!/bin/bash
DAY=`date +%Y%m%d` 定义日期变量
SIZE=`du -sh /etc` 定义目录大小变量
echo "Date: $DAY" >> /copyetc/etcinfo.txt 把日期输入信息文档
echo "Data Size: $SIZE" >> /copyetc/etcinfo.txt 把大小输入信息文档
cd /copyetc 改变目录
tar zcvf etcbackups-${DAY}.tar.gz /etc /copyetc/etcinfo.txt 压缩etc和信息文件
rm -f /copyetc/etcinfo.txt 删除信息文件
[root@CentOS6 copyetc]# vi etcbackups.sh 创建并编辑shell脚本
[root@CentOS6 copyetc]# chmod 755 etcbackups.sh 修改目录权限
[root@CentOS6 copyetc]# ./etcbackups.sh 执行
......执行过程
/copyetc/etcinfo.txt执行结尾
[root@CentOS6 copyetc]# ls查看
etcbackups20140707.tar.gz etcbackups.sh
[root@CentOS6 copyetc]#
Shell 编程实例
2010-05-06 17:14:34| 分类: shell |举报 |字号大中小 订阅
1.用Shell编程,判断一文件是不是字符设备文件,如果是将其拷贝到 /dev 目录下。
参考程序:
#!/bin/sh
FILENAME=
echo “Input file name:”
read FILENAME
if [ -c "$FILENAME" ]
then
cp $FILENAME /dev
fi
2.请下列shell程序加注释,并说明程序的功能和调用方法:#!/bin/sh
#!/bin/sh
#
# /etc/rc.d/rc.httpd
#
# Start/stop/restart the Apache web server.
#
# To make Apache start automatically at boot, make this
# file executable: chmod 755 /etc/rc.d/rc.httpd
#
case "$1" in
'start')
/usr/sbin/apachectl start ;;
'stop')
/usr/sbin/apachectl stop ;;
'restart')
/usr/sbin/apachectl restart ;;
*)
echo "usage $0 start|stop|restart" ;;
esac
参考答案:
(1)程序注释
#!/bin/sh 定义实用的shell
#
# /etc/rc.d/rc.httpd 注释行,凡是以星号开始的行均为注释行。
#
# Start/stop/restart the Apache web server.
#
# To make Apache start automatically at boot, make this
# file executable: chmod 755 /etc/rc.d/rc.httpd
#
case "$1" in #case结构开始,判断“位置参数”决定执行的操作。本程序携带一个“位置参数”,即$1
'start') #若位置参数为start
/usr/sbin/apachectl start ;; #启动httpd进程
'stop') #若位置参数为stop
/usr/sbin/apachectl stop ;; #关闭httpd进程
'restart') #若位置参数为stop
/usr/sbin/apachectl restart ;; #重新启动httpd进程
*) #若位置参数不是start、stop或restart时
echo "usage $0 start|stop|restart" ;; #显示命令提示信息:程序的调用方法
esac #case结构结束
(2)程序的功能是启动,停止或重新启动httpd进程
(3)程序的调用方式有三种:启动,停止和重新启动。
3.设计一个shell程序,添加一个新组为class1,然后添加属于这个组的30个用户,用户名的形式为stdxx,其中xx从01到30。
参考答案:
#!/bin/sh
i=1
groupadd class1
while [ $i -le 30 ]
do
if [ $i -le 9 ] ;then
USERNAME=stu0${i}
else
USERNAME=stu${i}
fi
useradd $USERNAME
mkdir /home/$USERNAME
chown -R $USERNAME /home/$USERNAME
chgrp -R class1 /home/$USERNAME
i=$(($i+1))
done
4.编写shell程序,实现自动删除50个账号的功能。账号名为stud1至stud50。
参考程序:
#!/bin/sh
i=1
while [ $i -le 50 ]
do
userdel -r stud${i}
i=$(($i+1 ))
done
5.某系统管理员需每天做一定的重复工作,请按照下列要求,编制一个解决方案:
(1)在下午4 :50删除/abc目录下的全部子目录和全部文件;
(2)从早8:00~下午6:00每小时读取/xyz目录下x1文件中每行第一个域的全部数据加入到/backup目录下的bak01.txt文件内;
(3)每逢星期一下午5:50将/data目录下的所有目录和文件归档并压缩为文件:backup.tar.gz;
(4)在下午5:55将IDE接口的CD-ROM卸载(假设:CD-ROM的设备名为hdc);
(5)在早晨8:00前开机后启动。
参考答案:
解决方案:
(1)用vi创建编辑一个名为prgx的crontab文件;
(2)prgx文件的内容:
50 16 * * * rm -r /abc/*
0 8-18/1 * * * cut -f1 /xyz/x1 >;>; /backup/bak01.txt
50 17 * * * tar zcvf backup.tar.gz /data
55 17 * * * umount /dev/hdc
(3)由超级用户登录,用crontab执行 prgx文件中的内容:
prgx;在每日早晨8:00之前开机后即可自动启动crontab。
6.设计一个shell程序,在每月第一天备份并压缩/etc目录的所有内容,存放在/root/bak目录里,且文件名为如下形式yymmdd_etc,yy为年,mm为月,dd为日。Shell程序fileback存放在/usr/bin目录下。
参考答案:
(1)编写shell程序fileback:
#!/bin/sh
DIRNAME=`ls /root | grep bak`
if [ -z "$DIRNAME" ] ; then
mkdir /root/bak
cd /root/bak
else
cd /root/bak
fi
YY=`date +%y`
MM=`date +%m`
DD=`date +%d`
BACKETC=$YY$MM$DD_etc.tar.gz
tar zcvf $BACKETC /etc
echo "fileback finished!"
(2)编写任务定时器:
echo "0 0 1 * * /bin/sh /usr/bin/fileback" >; /root/etcbakcron
crontab /root/etcbakcron
或使用crontab -e 命令添加定时任务:
0 1 * * * /bin/sh /usr/bin/fileback
7.有一普通用户想在每周日凌晨零点零分定期备份/user/backup到/tmp目录下,该用户应如何做?
参考答案:(1)第一种方法:
用户应使用crontab –e 命令创建crontab文件。格式如下:
0 0 * * sun cp –r /user/backup /tmp
(2)第二种方法:
用户先在自己目录下新建文件file,文件内容如下:
0 * * sun cp –r /user/backup /tmp
然后执行 crontab file 使生效。
8.设计一个Shell程序,在/userdata目录下建立50个目录,即user1~user50,并设置每个目录的权限,其中其他用户的权限为:读;文件所有者的权限为:读、写、执行;文件所有者所在组的权限为:读、执行。
参考答案: 建立程序 Pro16如下:
#!/bin/sh
i=1
while [ i -le 50 ]
do
if [ -d /userdata ];then
mkdir -p /userdata/user$i
chmod 754 /userdata/user$i
echo "user$i"
let "i = i + 1" (或i=$(($i+1))
else
mkdir /userdata
mkdir -p /userdata/user$i
chmod 754 /userdata/user$i
echo "user$i"
let "i = i + 1" (或i=$(($i+1))
fi
done