zoukankan      html  css  js  c++  java
  • shell脚本基础知识

    shell脚本基础知识

    author:headsen chen   2017-10-19   10:22:15  

    个人原创,根据老男孩教学视频及老男孩老师的shell编程书籍整理出来的,转载请注明。否则依法追究法律责任

    1,清除/VAR/LOG/MESSAGES日志的脚本

    #!/bin/bash
    # erase /var/log/message
    LOG_DIR=/var/log
    ROOT_UID=0

    if [ "$UID" -ne "$ROOT_UID" ]
    then
    echo "must be root can run this scripts"
    exit 1 #退出脚本
    fi

    #如果切换目录不成共则给出错误提示并退出脚本
    cd $LOG_DIR || {
    echo "cannot change to nessesary directory"
    exit 1
    }

    cat /dev/null >messages && {
    echo "logs cleaned up"
    exit 0 #退出之前返回0表示成功,返回1表示失败
    }

    echo "logs cleaned up fail." #当上一步执行成功后就exit了,就不会执行到这一步了,上一步没有成功,才会到这里。
    exit 1
    ~

    2,查看系统支持的SHELL
    [root@paris a]# cat /etc/shells
    /bin/sh
    /bin/bash
    /sbin/nologin
    /bin/dash
    /bin/tcsh
    /bin/csh

    3,CENTOS LINUX默认的shell是什么:bash
    [root@paris a]# echo $SHELL
    /bin/bash

    4,脚本的第一行:#!/bin/bash 确定由哪个程序来解释这个脚本,这里就是bash.
    [root@paris a]# ll /bin/sh
    lrwxrwxrwx. 1 root root 4 7月 29 04:50 /bin/sh -> bash
    所以,第一行写成 #!/bin/sh 也可以,如果使用这个出现异常,就改用#!/bin/bash

    [root@paris a]# bash --version
    GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
    Copyright (C) 2009 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
    This is free software; you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.

    升级shell
    [root@paris a]# yum -y update bash
    [root@paris a]# rpm -qa bash
    bash-4.1.2-48.el6.x86_64

    centos系统中默认就是以/bin/bash作为解释器,
    脚本中尽量不要用中文

    5,shell脚本执行过程
    shell脚本运行时,先加载环境变量,顺序是:/etc/profile ---> ~/.bash_profile -----> /etc/bashrc等,完了后再加载脚本内容
    shell执行顺序:从上至下,从左到右,如果碰到子脚本(脚本嵌套),先执行子脚本,等待子脚本执行完成后再执行父脚本。

    6,shell脚本执行方法
    6.1 bash/sh xxx.sh 当xxx.sh 本身没有+x的权限时也可以执行,这时用.或source 执行不了。---推荐方法
    6.2 chmod +x xxx.sh 才可以:path/xxx.sh
    ./xxx.sh
    例:[root@paris a]# chmod +x erase_log.sh
    [root@paris a]# ll
    总用量 4
    -rwxr-xr-x 1 root root 478 7月 29 19:16 erase_log.sh
    [root@paris a]# /tmp/a/erase_log.sh
    logs cleaned up
    [root@paris a]# ./erase_log.sh
    logs cleaned up
    6.3 source xxx.sh 和 . xxx.sh 用途完全相同,在运行时会将脚本中的变量值和函数传递到当前的父shell中。
    source和.也可以执行没有+x权限的脚本。
    例:source /etc/profile
    source /home/oracle/.bash_profile ------ 加载oracle的环境变量
    6.4 cat xxx.sh |bash --------- 将这个文件中的内容交给bash处理,例如处理开机命令 = cat xxx.sh |sh
    bash <xxx.sh -----也是用bash来处理这个文件。

    7,脚本常识定义:

    #!/bin/bash
    # author:chen
    # date: 2017-07-29
    # description: this scripts function is ...
    # version: 1.1
    ...
    尽量不要用中文:防止切换系统后中文乱码
    有中文的情况下,对系统的字符集调整:
    #export LANG="zh_CN.UTF-8"

    脚本中的单引号,双引号,反引号必须是英文状态下的符号。

    8,特殊的参数变量

    $# --- shell脚本后接的参数个数

    $0 --- shell脚本的文件路径和文件名

    $n --- 获取当前执行的shell脚本的第n个参数

    $* --- 获取当前脚本中所有的传参参数

    $@ --- ............................

    总结:$* = $@
    "$*" ="$1 $2 $3 ..."
    "$@" = "$1" "$2" "$3" ...
    $? --- 获取执行上一个指令的状态返回值 (0:成功,非0:失败)

    $$ --- 获取当前shell的pid号

    $?的应用:源码包安装时判断过程是否成功:
    #./configure
    #echo $? -------------- 0 即成功
    #make
    #echo $? --------------- ...
    #make install
    #echo $? --------------- ...

    例:cat a.sh
    [ $# -ne 2 ] && {
    echo "must be two args." # arg:元素
    exit 119 #终止程序运行,并以119的状态值退出程序,将119赋值给shell的$?变量
    }

    9,参考脚本:cat /etc/init.d/rpcbind
    [root@paris a]# cat /etc/init.d/rpcbind
    #! /bin/sh
    #
    # rpcbind Start/Stop RPCbind
    #
    # chkconfig: 2345 13 87
    # description: The rpcbind utility is a server that converts RPC program
    # numbers into universal addresses. It must be running on the
    # host to be able to make RPC calls on a server on that machine.
    #
    # processname: rpcbind
    # probe: true
    # config: /etc/sysconfig/rpcbind


    # This is an interactive program, we need the current locale # 这是一个交互程序,locale:场所,这里指目录
    [ -f /etc/profile.d/lang.sh ] && . /etc/profile.d/lang.sh # .执行lang.sh这个脚本
    # We can't Japanese on normal console at boot time, so force LANG=C.
    if [ "$LANG" = "ja" -o "$LANG" = "ja_JP.eucJP" ]; then
    if [ "$TERM" = "linux" ] ; then
    LANG=C
    fi
    fi

    # Source function library.
    . /etc/init.d/functions

    # Source networking configuration.
    [ -f /etc/sysconfig/network ] && . /etc/sysconfig/network

    prog="rpcbind"
    [ -f /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog

    RETVAL=0
    uid=`id | cut -d( -f1 | cut -d= -f2`

    start() {
    # Check that networking is up.
    [ "$NETWORKING" = "yes" ] || exit 6

    [ -f /sbin/$prog ] || exit 5

    # Make sure the rpcbind is not already running.
    if status $prog > /dev/null ; then
    exit 0
    fi

    # Only root can start the service
    [ $uid -ne 0 ] && exit 4

    echo -n $"Starting $prog: "
    daemon $prog $1 "$RPCBIND_ARGS"
    RETVAL=$?
    echo
    if [ $RETVAL -eq 0 ] ; then
    touch /var/lock/subsys/$prog
    [ ! -f /var/run/rpcbind.pid ] &&
    /sbin/pidof $prog > /var/run/rpcbind.pid
    fi
    return $RETVAL
    }


    stop() {
    echo -n $"Stopping $prog: "
    killproc $prog
    RETVAL=$?
    echo
    [ $RETVAL -eq 0 ] && {
    rm -f /var/lock/subsys/$prog
    rm -f /var/run/rpcbind*
    }
    return $RETVAL
    }

    # See how we were called.
    case "$1" in
    start)
    start
    RETVAL=$?
    ;;
    stop)
    stop
    RETVAL=$?
    ;;
    status)
    status $prog
    RETVAL=$?
    ;;
    restart | reload| force-reload)
    stop
    start
    RETVAL=$?
    ;;
    condrestart | try-restart)
    if [ -f /var/lock/subsys/$prog ]; then
    stop
    start -w
    RETVAL=$?
    fi
    ;;
    *)
    echo $"Usage: $0 {start|stop|status|restart|reload|force-reload|condrestart|try-restart}"
    RETVAL=2
    ;;
    esac

    exit $RETVAL #如果返回值不等于0,则跳过条件表达式的判断,在这里直接作为返回值传给执行stop函数的脚本。

    ........................................................................................................................

    10,echo的特殊参数应用实例

    -n 不换行输出内容,默认是换行输出内容
    -e 解析转义字符
    常见转义字符: 换行
    回车
    制表符tab
     退格

    [root@paris a]# echo oldboy;echo oldgirl
    oldboy
    oldgirl
    [root@paris a]# echo -n oldboy;echo oldgirl
    oldboyoldgirl
    [root@paris a]# echo -e "oldboy oldgril oldboy oldgirl"
    oldboy oldgril
    oldboy oldgirl
    [root@paris a]# echo -e "123" -------------- 就是这个符号前面的这个字符不显示
    23

    11,exec
    exec 能够在不创建新的子进程的前提下,转去执行指定的命令,指定的命令完成后,该进程(最初的shell)就终止了
    [root@paris 桌面]# useradd chen
    [root@paris 桌面]# su - chen
    [chen@paris ~]$ exec date
    2017年 07月 29日 星期六 21:28:49 CST
    [root@paris 桌面]#

    12,shift
    在shell中,将参数的位置向左移动,原来的$3变成$2,$1就消失了

    [root@paris 桌面]# vim b.sh

    echo $1 $2
    if [ $# -eq 2 ];then
    shift
    echo $1
    fi

    [root@paris 桌面]# sh b.sh 1 2
    1 2
    2

    13,exit
    退出shell脚本,后面可以指定一个数位作为返回状态,该数值赋值给$?
    #cat b.sh

    echo $1 $2
    if [ $# -eq 2 ];then
    shift
    echo $1
    fi
    exit 5
    [root@shiyan tmp]# sh b.sh 5 9
    5 9
    9
    [root@shiyan tmp]# echo $?
    5


    14,打印shell变量的长度
    [root@paris a]# OLDBOY="I am oldboy"
    [root@paris a]# echo ${OLDBOY}
    I am oldboy
    [root@paris a]# echo OLDBOY
    OLDBOY
    [root@paris a]# echo $OLDBOY
    I am oldboy
    [root@paris a]# echo ${#OLDBOY} ------------------- { }大括号内的必需是变量,不能是具体的字符
    11
    [root@paris a]# echo $OLDBOY |wc -L
    11
    [root@paris a]# expr length "$OLDBOY" -------------------- 引号内必需是变量。不能是具体的字符
    11
    [root@paris a]# expr length "asdfadgagahasf" --------------- 引号内可以是具体的字符
    14

    [root@paris a]# echo "$OLDBOY" |awk '{print length($0)}'
    11
    [root@paris a]# echo "$OLDBOY" |awk '{print length}'
    11

    wc -l用于统计行数
    wc -L用于统计单行的字符数
    [root@paris a]# echo lsafjajsf |wc -l
    1
    [root@paris a]# echo lsafjajsf |wc -L
    9

    awk可以统计每行的字符数
    [root@paris a]# cat b.sh
    echo $1 $2
    if [ $# -eq 2 ];then
    shift
    echo $1
    fi
    [root@paris a]# cat b.sh |awk '{print length}'
    10
    20
    8
    9
    2
    [root@shiyan tmp]# cat b.sh |awk '{print length $0}'
    10echo $1 $2
    20if [ $# -eq 2 ];then
    8 shift
    10 echo $1
    2fi
    6exit 5


    15,将下列字符串中的字符数小于等于6的单词打印出来:i am oldboy linux,welcome to our training
    [root@paris a]# echo "i am oldboy linux,welcome to our training" |tr "," " "
    # vim count_words.sh

    #!/bin/bash
    # print words where counts less than 6
    for i in i am oldboy linux welcome to our training
    do
    a=`expr length "$i"`
    if [ $a -le 6 ];then
    echo "$i"
    fi
    done

    16,截取变量的字符,从第二个字符之后开始
    [root@paris a]# echo $OLDBOY
    I am oldboy
    [root@paris a]# echo ${OLDBOY:2}
    am oldboy
    [root@paris a]# echo ${OLDBOY:2:2}
    am


    17,替换变量中的内容
    [root@paris a]# OLDBOY="I am oldboy,yes,oldboy"
    [root@paris a]# echo ${OLDBOY/oldboy/oldgirl} ----------- / 匹配行中的第一个字符
    I am oldgirl,yes,oldboy
    [root@paris a]# echo ${OLDBOY//oldboy/oldgirl} ----------- // 匹配行中的全部字符串
    I am oldgirl,yes,oldgirl
    [root@paris a]#

    18,去掉下面文件中的_finished字符串
    [root@paris a]# touch 20170730_{1..10}_finished.jpg
    [root@paris a]# ls
    20170730_10_finished.jpg 20170730_5_finished.jpg b.sh
    20170730_1_finished.jpg 20170730_6_finished.jpg b.txt
    20170730_2_finished.jpg 20170730_7_finished.jpg count_words.sh
    20170730_3_finished.jpg 20170730_8_finished.jpg erase_log.sh
    20170730_4_finished.jpg 20170730_9_finished.jpg

    [root@paris a]# rename _finished. . *.jpg ---------------------rename a b filename (a换成b)

    [root@paris a]# ls
    20170730_10.jpg 20170730_3.jpg 20170730_6.jpg 20170730_9.jpg count_words.sh
    20170730_1.jpg 20170730_4.jpg 20170730_7.jpg b.sh erase_log.sh
    20170730_2.jpg 20170730_5.jpg 20170730_8.jpg b.txt

    19, 删除7天前的过期备份数据
    vim del.sh
    #!/bin/bash
    find ${path-/tmp} -name "*.tar.gz" -type f -mtime +7 |xargs rm -f
    #=find ${path:-/tmp} -name "*.tar.gz" -type f -mtime +7 |xargs rm -f

    当系统里定义了$path时,就去$path里找文件,当系统没有定义$path时,就去/tmp下去找(用/tmp代替当前的变量值)

    20,shell中的算术运算
    = 赋值
    += 累积加 a+=1 -----> a=a+1
    -= 累积减 a-=1 -----> a=a-1

    shell中的算术运算符号
    (()) 整数运算符,效率高
    let 和(())一样,整数运算符
    expr 整数运算
    $[]整数运算
    bc 整数和小数运算
    awk 整数和小数

    21,(())应用举例:
    [root@paris a]# echo $((1+1))
    2
    [root@paris a]# echo $((6-3))
    3
    [root@paris a]# ((i=5)) --------------变量放在了括号的里边
    [root@paris a]# ((i=i*2))
    [root@paris a]# echo $i
    10
    [root@paris a]# ((a=1+2**3-4%3))
    [root@paris a]# echo $a
    8
    [root@paris a]# echo $((1+2**3-4%3)) ----------- 注意:$不要少了。少了就没有值了
    8
    [root@paris a]# a=$((1+2**3-4%3)) -------------变量放在了括号的外边
    [root@paris a]# echo $a
    8
    [root@paris a]# echo $((100*(100+1)/2)) --------- 计算1+2+3...+100的和,括号外加$
    5050

    [root@paris a]# echo ((1+2**3-4%3)) -------- 少了$,所以会报错
    bash: syntax error near unexpected token `('
    [root@paris a]# ((1+2**3-4%3)) ---------没有任何结果出来的

    [root@paris a]# a=8
    [root@paris a]# echo $((a=a+1)) ------------括号中的a可以加$,也可以不加$,都可以。
    9
    [root@paris a]# echo $((a=a-1))
    8
    [root@paris a]# echo $((a+=1))
    9

    比较运算:
    [root@paris a]# echo $((3<8)) ------------- 正确就返回1,错误就返回0(和shell的上个进程执行结果$?相反)
    1
    [root@paris a]# echo $((3>8))
    0
    [root@paris a]# echo $((8=8)) --------- = 在Linux中表示赋值的意思,此时会报语法错误
    bash: 8=8: attempted assignment to non-variable (error token is "=8")
    [root@paris a]# echo $((8==8)) ---------- == 判断是否相等
    1


    20,脚本基础内容补充 :
    read variable #读取变量给variable
    read x y
    #可同时读取多个变量
    read
    #自动读给REPLY
    read –p “Please input: ”
    #自动读给REPLY[root@localhost shell]# cat d.sh
    #!/bin/bash
    read -p "three variable: " x y z
    echo $x
    echo $y
    echo $z
    read
    echo $REPLY
    read -p "please input: "
    echo $REPLY

  • 相关阅读:
    网络编程中 TCP 半开连接和TIME_WAIT 学习
    redis中的小秘密和持久化小细节
    排序
    Es官方文档整理-3.Doc Values和FieldData
    Es官方文档整理-2.分片内部原理
    Elasticsearch doc_value认识
    路边停靠 贴边停车不蹭轮胎的技巧
    mybatis 连接数据库
    putIfAbsent
    Hive与HBase区别 大墨垂杨
  • 原文地址:https://www.cnblogs.com/kaishirenshi/p/7691070.html
Copyright © 2011-2022 走看看