设为首页 收藏本站
查看: 940|回复: 0

Bash Shell脚本编程笔记总结(一)

[复制链接]

尚未签到

发表于 2018-8-25 07:36:05 | 显示全部楼层 |阅读模式
  
  本文是上课笔记总结,涉及细节知识点会在以后文章说明!
  bash脚本编程:
  脚本程序:解释器解释执行;
  shell: 交互式接口;编程环境;
  shell: 能够提供一些内部命令,并且能通过PATH环境变量找到外部命令;把命令提交给内核启动为进程;
  编程环境:
  流程控制语句:
  顺序执行;
  循环执行;
  选择执行;
  条件测试:真、假
  $?
  命令的状态结果:
  0: 真
  1-255: 假
  过程式的编程语言的元素:变量、流程、函数、数组
  变量:局部变量、本地变量、环境变量、位置参数变量、特殊变量
  变量:
  数值型:整型、浮点型、布尔型
  字符型:字符串
  bash变量是弱类型;默认字符型;
  变量引用:${VAR_NAME}
  引号:
  弱引用:""
  强引用:''
  命令引用:``
  声明某变量为整型变量:
let VAR_NAME=VALUE  
declare -i VAR_NAME=VALUE
  声明某变量为环境变量:
export VAR_NAME=VALUE  
declare -x VAR_NAME=VALUE
  脚本的编写格式:
  第一行:写明解释器; #!/bin/bash
  注释行:所有以#开头的行均为注释行;会被解释器忽略;
  执行脚本:
  赋予执行权限;指明路径执行;
  直接传递脚本给bash解释器
  bash的选项:
  -n: 测试脚本中是否有语法 错误;
  -x: 调试执行;
  算术运算:
$[EXPRESSION]  
let VAR_NAME=EXPRESSION
  
$((EXPRESSION))
  
$(expr argu1 argu2 argu3)
  流程控制之一:for循环
  将一段代码反复执行;
  表达式:
for VAR in LIST; do  
STATEMENT1
  
...
  
done
for VAR in LIST; do statement1; statement2; ...; donefor ((初始化循环控制变量;循环条件;修正表达式)); do  
循环体
  
done
  进入条件; 退出条件;
  循环体;STATEMENT1
  睡眠:sleep [n]
  循环次数:为列表中的元素的个数;
  LIST:列表,包含至少一个元素的字符串集合;
  (1) 直接给出;
  (2) 数值列表:
  (a) {start..end}
  例如:{1..10}
  (b) seq [start [step]] end
seq LAST  
seq FIRST LAST
  
seq FIRST STEP LAST
  (3) 返回列表的命令;
  (4) globbing;
  (5) 变量引用;
  $*, $@
  例如:添加3个用户,user1, user2, user3; 密码同用户名;
#vi useradd.sh  
#!/bin/bash
  
for username in user1 user2 user3; do
  
useradd $username
  
echo $username |passwd --stdin $username
  
done
  例如:添加9个用户,user101...user109;密码同用户名;
#vi useradd2.sh  
#!/bin/bash
  
for i in {1..9}; do
  
useradd user10$i
  
echo user10$i |passwd --stdin user10$i
  
done
  练习:于/tmp/test目录中创建10个空文件f1,.., f10;
#vi addfile.sh  
#!/bin/bash
  
directory=/tmp/test-$(date '+%Y%m%h')
  
mkdir $directory
  
for i in {1..10} ; do
  
touch $directory/f$i
  
done
  练习:写一个脚本,
  (1) 创建"/tmp/test-当前时间"目录;
  (2) 添加10用户tuser1,.., tuser10;
  (3) 在"/tmp/test-当前时间"目录中,创建10空文件f1,...,f10;
  (4) 修改f1的属主为tuser1;依次类推;
#vi creatdir.sh  
#!/bin/bash
  
dir=/tmp/test-$(date '+%F-%H-%S')
  
mkdir $dir
  
for i in {1..10} ; do
  
        useradd testuser$i
  
        touch $dir/f$i
  
        chown testuser$i $dir/f$i
  
done
  
rm -rf $dir
  
userdel testuser$i
  练习:求100以内所有正整数之和;
#vi plus.sh  
#!/bin/bash
  
sum=0
  
for i in `seq 100`;do
  
sum=$(($sum+$i))
  
done
  
echo $sum
  练习:求100以内所有偶数之和;以及所有奇数之和;
#!/bin/bash  
declare -i sum=0
  
for i in `seq 1 2 100`;do
  
        sum=$(($sum+$i))
  
done
  
echo $sum
  
declare -i sum1=0
  
for i in `seq 2 2 100`; do
  
        sum1=$(($sum1+$i))
  
done
  
echo $sum1
  
练习5:计算当前系统上所有用户ID之和;
  
#!/bin/bash
  
sum=0
  
for i in `cut -d: -f3 /etc/passwd` ; do
  
        sum=$(($sum+$i))
  
done
  
echo $sum
  练习:传递参数(文本文件路径)给脚本,统计所有文件的空白行数之和;显示此次共对多少文件进行统计;
#!/bin/bash  
sum=0
  
num=0
  
echo $#
  
for i in `seq 1 $# `; do
  
        num=`grep '^$' $1 |wc -l`
  
        sum=$(($num+$sum))
  
        shift
  
done
  
echo  $sum
  练习:显示当前系统所有默认shell为bash的用户的总数;并统计此些用户ID之和;

  for>#!/bin/bash  
sum=0
  
num=0
  
for i in `grep 'bash$' /etc/passwd |cut -d: -f3` ; do
  
        sum=$(($sum+$i))
  
        num=$(($num+1))
  
done
  for的几种特殊情况:
  (1) for省略,会自动获取脚本参数列表;
  (2) C编程风格:
  for ((变量赋值;循环条件;修正表达式)); do
  CMD1
  CMD2
  done
  (3) 循环嵌套:
  for i in [LIST1]; do
  CMD1
  for j in [LIST2]; do
  CMD2
  ...
  done
  done
  练习:写一个脚本
  (1) ping 172.16.X.Y内的所有主机;
  172.16.0-255.1-254
for i in {0..255}; do  
    for j in {1..254}; do
  
        ping -c1 -w1 172.16.$i.$j
  
    done
  
done
  练习:写个脚本
  (1) 传递一些目录给脚本;
  (2) 逐个显示每个目录下的所有一级文件的内容类型;
  (3) 统计一个有多少个目录;一共显示了多少个文件;
#!/bin/bash  
#
  
declare -i dirs=0
  
declare -i files=0
  
for d in $*; do
  
    for f in $d/*; do
  
        file $f
  
        let files++
  
    done
  
    let dirs++
  
done
  
echo "Directories: $dirs."
  
echo "Files: $files."
  bash命令退出和退出状态码
  命令在bash中执行结束退出时,其执行成功与否可通过退出状态码来记录
#echo $?  脚本的退出状态码取决于执行的最后一条命令;自定义退出状态码:
  exit #
  成功:0
  失败:1-255
#!/bin/bash  
ls /varr
  
retval=$?
  
echo 'hello'
  
exit $retvel
  以ls /varr的结果状态为退出状态
  注意:提前退出脚本,也可使用exit命令实现
  bash 脚本编程之条件测试:
  if/then结构
  条件测试:
test EXPRESSION  
[ EXPRESSION ]
  
[[ EXPRESSION ]]
  COMMAND:使用的是命令退出状态码
  1.使用命令执行结果
  a.使用命令引用
  b.使用比较操作符
  例如:
[  `id -u $username ` -lt  500 ]  
userid=`id -u $username`
  
[ $userid  -lt 500]
  2.使用命令的退出状态码
  a.先运行命令
  b.引用状态码
  引用方式两种:
  1.if COMMAND &>/dev/null;then
  引用的是命令运行的退出状态码
  注意:COMMAND不能被使用命令引用,COMMAND的执行结果通常没有意义,所以其结果通常(&>)被定向至/dev/null
  2.先执行命令,后判断退出状态码是否为0
  COMMAND
retval=$?  
if [ $? -eq 0 ] ; then
  测试表达式:
  (1) 整数测试;例如:1 B
  A < B
  A >= B
  A " /etc/passwd | cut -d: -f7` =~ /bin/.*sh$ ]]; then
  
    echo "a user can log system."
  
else
  
    echo "a user cannot log."
  
fi
  组合测试条件2:
  短路操作符
  与:COMMAND1 && COMMAND2
  COMMAND1的退出状态如果为假,则COMMAND2不用运行,即可有最终结果;
  或:COMMAND1 || COMMAND2
  COMMAND1的退出状态如果为真,则COMMAND2不用运行,即可有最终结果;
  非:! COMMAND
[ ! -d /tmp/test ] && mkdir /tmp/test^C  
[ -d /tmp/test ] || mkdir /tmp/test
  练习:写一个脚本,完成如下任务:
  (1) 如果httpd进程或nginx进程处于运行中,则显示“web server started.”,并显示其监听的端口;
  (2) 否则显示“no web server.”;
if pidof httpd &> /dev/null && pidof nginx &> /dev/null;  交互式脚本:
  read [OPTIONS] [name ...]
  -p "PROMPT"
  -t #: 超时时长
  给变量以默认值:
  [ -z "$VAR" ] && VAR=VALUE
  练习:显示如下菜单给用户
  cpu) show cpu infomation;
  mem) show memory infomation;
  disk) show disk infomation;
  *) quit
  提示用户键入选项:
  (1) cpu: 显示CPU相关的信息
  (2) mem: 显示内存相关的信息
  (3) disk: 列出磁盘设备
  (4) 其它任何信息,即为退出脚本
#!/bin/bash  
#
  
cat  /dev/null
  
    status=$?
  
done
  
echo "centos is logged on."
  方法二:简化版
#!/bin/bash  
#
  
declare -i status=0
  
until who | grep "centos" &> /dev/null; do
  
    sleep 5
  
done
  
echo "centos is logged on."
  方法三:使用死循环
#!/bin/bash  
#
  
while true; do
  
    who | grep "centos" &> /dev/null
  
    if [ $? -eq 0 ];then
  
break
  
    fi
  
    sleep 5
  
done
  
echo "centos is logged."
  while的特殊用法:遍历指定文件的每一行
  while read line; do
  循环体
  done < /path/from/somefile
  练习:找出其UID为偶数的所有用户的用户名;并显示其ID号;
#!/bin/bash  
#
  
file=/etc/passwd
  
while read line; do
  
    userid=`echo $line | cut -d: -f3`
  
    if [ $[$userid%2] -eq 0 ]; then
  
echo $line | cut -d: -f1,3
  
    fi
  
done < $file
  练习:输出给定的文件的偶数行的行号,以及其行内信息统统改为大写字母输出;
#!/bin/bash  
declare -i i=1
  
while read line; do
  
    if [ $[$i%2] -eq 0 ]; then
  
    echo -n "$i "
  
    echo $line | tr 'a-z' 'A-Z'
  
    fi
  
    let i++
  
done < /path/from/somefile
  练习:显示如下菜单给用户
  cpu) cpuifno
  mem) memory infomation
  disk) disk infomation
  quit) quit
  (1) 用户给定的选项后,显示相应的信息;而后提示用户再次选择;
  (2) 非正确选择也提示用户重新选择,并说明,如果想退出请输入"quit";
#!/bin/bash  
#
  
while true; do
  
cat  /dev/null && return 2
  
    grep "^$1\>" /etc/passwd | cut -d: -f7
  
    [ $? -eq 0 ] && return 0 || return 3
  
}
  
while true; do
  
    read -p "Enter a username: " username
  
    [ "$username" == 'quit' ] && break
  
    showuserinfo $username
  
    [ $? -ne 0 ] && echo "There is something wrong."
  
done
  练习:利用函数实现打印九九乘法表;
#!/bin/bash  
func() {
  
declare i=1
  
declare j=1
  
while [ $i -le 9 ] ; do
  
        while [ $j -le 9 ] ; do
  
                if [ $j -gt $i ] ; then
  
                        break
  
                fi
  
                echo -e -n "{$j}x$i=$[$i*$j]\t"
  
                let j++
  
        done
  
                echo
  
                let j=1
  
                let i++
  
        done
  
}
  
func
  练习:写一个脚本,完成如下功能(使用函数):
  1、提示用户输入一个可执行命令;
  2、获取这个命令所依赖的所有库文件(使用ldd命令);
  3、复制命令至/mnt/sysroot/对应的目录中
  解释:假设,如果复制的是cat命令,其可执行程序的路径是/bin/cat,那么就要将/bin/cat复制到/mnt/sysroot/bin/目录中,如果复制的是useradd命令,而useradd的可执行文件路径为/usr/sbin/useradd,那么就要将其复制到/mnt/sysroot/usr/sbin/目录中;
  4、复制各库文件至/mnt/sysroot/对应的目录中;
#!/bin/bash  
#
  
target=/mnt/sysroot
  
[ -d $target ] || mkdir $target
  
preCmd() {
  
    if which $1 &> /dev/null; then
  
cmdpath=$(which --skip-alias $1)
  
return 0
  
    else
  
echo "No such command."
  
return 1
  
    fi
  
}
  
cmdCopy() {
  
    cmddir=$(dirname $cmdpath)
  
    [ -d $target/$cmddir ] || mkdir -p $target/$cmddir
  
    [ -f $target/$cmdpath ] || cp $1 $target/$cmddir
  
    return 0
  
}
  
libCopy() {
  
    for lib in $(ldd $1 | grep -E -o "/[^[:space:]]+"); do
  
libdir=$(dirname $lib)
  
[ -d $target/$libdir ] || mkdir -p $target/$libdir
  
[ -f $target/$lib ] || cp $lib $target/$libdir
  
    done
  
    return 0
  
}
  
main() {
  
    while true; do
  
        read -p "Plz enter a command(quit for quiting): " cmd
  
        [ "$cmd" == 'quit' ] && break
  
        preCmd $cmd
  
        if [ $? -eq 0 ]; then
  
   cmdCopy $cmdpath
  
            libCopy $cmdpath
  
        fi
  
    done
  
}
  
main
  变量的作用域
  本地变量:整个脚本,在脚本的函数中也可调用,也可修改;
  局部变量:函数调用的整个生命周期;
  local VAR=VALUE
  函数递归
  函数直接或间接调用函数自身;
  1 1 2 3 5 8 13
  阶乘:10!
  n(n-1)!
  n(n-1)(n-2)!
  阶乘函数:
  fact() {
  if [ $1 -eq 0 -o $1 -eq 1 ]; then
  echo 1
  else
  echo $[$1*$(fact $[$1-1])]
  fi
  }
  下一篇接:Bash Shell脚本编程笔记总结(二)



运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-556129-1-1.html 上篇帖子: linux下用shell将文件名进行大小写转换 下篇帖子: shell分析swap分区被哪些程序占用(stress模拟环境)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表