zoukankan      html  css  js  c++  java
  • Shell编程

    shell用于解释执行用户命令,用法分为Interactive和Batch.

    shell script中有多条shell命令,批量执行,同时加入编程语言中常用的变量,

    流程控制语句,这样看起来写shell script就像编程,但是本质上只是一系列shell命令的集合.

    常见的shell版本

    • sh linux unix系统都有
    • tcsh FreeBSD macOS x使用
    • bash linux发行版标配

    查看用户对应的shell类型

    mark@ocarina:~$ more /etc/passwd|grep mark
    mark:x:1000:1000:mark,,,:/home/mark:/bin/bash
    # mark用户对应的shell是bash
    

    输入命令后,一般shell会fork开启新进程exec该命令,shell的内建命令是例外.

    执行builtin命令相当于调用shell进程中的一个函数,不fork.

    内建命令不fork但是有Exit Status,0表示成功,非0表示失败,状态码可以用$?读取.

    常见内建命令:

    export  for  while  shift if  eval [
    

    which命令查不到程序文件所在位置的命令都是内建命令,这些命令没有man手册.

    要在man手册中查这些命令man bash-builtins

    执行脚本

    #! /bin/bash
    #在shell中#是注释标识符
    #在第一行的  #! 是shebang符号  表示以./xx.sh执行时由那个文件来执行
    echo hello shell
    ###########################编写脚本
    
    $ chmod a+x test.sh # 添加执行权限
    $ ./test.sh # 由/bin/bash执行
    hello shell # echo的输出结果
    

    执行脚本的方式

    • bash/sh test.sh
    • source test.sh 交互式执行 不fork
    • . test.sh 这个.和source一样是内建命令,同样也是Interactive执行

    shell脚本一行可以有多个命令,用;分隔.

    命令使用()以fork方式执行,如(cd ..;ls -l ),如果没有()会以interactive执行

    变量

    变量名必须=大写字母+下划线

    环境变量

    可以从father进程传给son进程

    环境变量可以从当前shell进程传给fork出来的进程

    printenv查看当前shell进程中的环境变量

    本地变量

    只处在与当前shell进程,set显示当前shell进程中定义的所有变量(local+env)和函数

    环境变量在任何进程中可见

    本地变量只在shell进程中可见

    在shell中环境变量与本地变量定义及使用方法相似.

    定义或赋值一个变量

    VAR_NAME=value # 这里的=号两边是绝对不能有空格的
    

    本地变量导出为环境变量

    export VAR_NAME
    

    定义一个本地变量同时导出

    export PATH=/usr/local
    

    删除变量(local+env)

    unset VAR_NAME
    

    取变量的值

    ${VAR_NAME}  #推荐使用这种
    $VAR_NAME
    # shell中的变量无需指定类型  本质上都是字符串
    # 变量无需先定义后使用  对未定义的变量取值返回空字符串
    

    代换

    Wildcard

    文件名代换(Globbing)

    Wildcard(通配符),和正则规则是一样的

    * ? [ ]

    $()

    命令代换,先执行命令,再将结果赋值给变量,将输出结果代换到命令中

    **` 或$() **

    $ DATE=`date`
    $ echo $DATE
    
    $ DATE=$(date) # 推荐使用这种方式
    $ echo $DATE
    

    $[]

    算术代换: $(()) 或 $[]

    ~$ echo $[8#10+1]  # 10进制 8+1
    9
    ~$ echo $[8#16+1]  # 16进制8+1
    15
    

    单引号与双引号

    • 单引号,保存引号中内容的字面值,包括 回车
    • 单引号内不得再出现单引号
    • 单引号必须配对
    • 双引号防止通配符扩展,允许变量扩展
    • 双引号内的变量还是变量,而不是像单引号一样是字面值
    ~$ DT=$(date)
    ~$ echo "${DT}"
    2019年 01月 25日 星期五 22:07:57 CST
    ~$ echo '${DT}'
    ${DT}
    

    所有的取值操作都应该放在双引号中,like "${VAR}"

    语法

    条件测试

    • test
    • [

    测试结果为真 exit status=0 else 1

    ~$ var=2
    ~$ test ${var} -lt 1
    ~$ echo $?
    1
    ~$ test ${var} -lt 8
    ~$ echo $?
    0
    ~$ test ${var} -lte 2 # 用不了
    bash: test: -lte: 需要二元表达式
    
    
    ~$ [ ${var} -lt 2 ] # [空格参数1空格参数2空格参数3空格参数4   参数4是]
    ~$ echo $?
    1
    

    常用测试命令:

    [ -d DIR ]              如果DIR存在并且是一个目录则为真
    [ -f FILE ]             如果FILE存在且是一个普通文件则为真
    [ -z STRING ]           如果STRING的长度为零则为真
    [ -n STRING ]           如果STRING的长度非零则为真
    [ STRING1 = STRING2 ]   如果两个字符串相同则为真
    [ STRING1 != STRING2 ]  如果字符串不相同则为真
    [ ARG1 OP ARG2 ]        ARG1和ARG2应该是整数或者取值为整数的变量,OP是-eq(等于)-ne(不等于)-lt(小于)-le(小于等于)-gt(大于)-ge(大于等于)之中的一个
    

    测试条件之间的 或 与 非

    带与、或、非的测试命令
    
    [ ! EXPR ]          EXPR可以是上表中的任意一种测试条件,!表示逻辑反
    [ EXPR1 -a EXPR2 ]  EXPR1和EXPR2可以是上表中的任意一种测试条件,-a表示逻辑与
    [ EXPR1 -o EXPR2 ]  EXPR1和EXPR2可以是上表中的任意一种测试条件,-o表示逻辑或
    

    if/then/elif/else/fi

    #! /bin/bash
    echo "Please give me a number >"
    read VR # 读取用户输入 赋值给变量VR
    # 变量VR的值与100比较
    if [ "${VR}" -lt 100 ]; then
        echo "${VR} < 100"
    else 
    	echo "${VR} > 100"
    fi
    
    if [ -f /bin/bash ]
    then echo "/bin/bash is a file"
    else echo "/bin/bash is not a file"
    fi
    
    if :; then echo "always true";fi # : 是特殊命令 返回值为0 永远为真
    
    echo "are you stupid?"
    read Y_N
    if [ "${Y_N}" = "yes" ]; then
        echo "hi,stupid."
    elif [ "${Y_N}" = "no" ]; then
        echo "oh,my deer."
    else
        echo "stupid is as stupid does."
        exit 1
    fi
    exit 0
    

    shell中的&&和||和java中的相似

    -a shell中的and -oshell中的or

    使用起来和&&和||等价

    但是

    &&和||还有一种用法,就是由前面部分的测试结果决定后半部分的语句是否执行,相当于

    && if ...then...

    || if not ...then...

    test "$(whoami)" != "root" && echo "need root privliges"; exit 1
    test "$(whoami)" == "root" || echo "need root privliges"; exit 1
    

    case/esac

    Shell的case可以匹配字符串和Wildcard

    每个匹配分支可以有若干条命令,末尾必须以;;结束

    执行时找到第一个匹配的分支并执行相应的命令,然后直接跳到esac之后,不需要像C语言一样用break跳出

    echo "something you like..."
    read n
    case "${n}" in
    bee)
        echo "busy as a bee";;
    dog)
        echo "日了狗了";;
    cat)
        echo "找只猫来";;
    *)
        echo "不懂你输入的是什么"
        exit 1;;
    esac
    exit 0
    

    shell中获取命令行参数${1}取第一个参数,后面的用2,3,4,5取

    case "${1}" in
    start)
        echo "服务器启动成功.";;
    stop)
        echo "成功杀掉服务器进程";;
    restart)
        echo "服务器重启好了.";;
    *)
        echo "无效的命令行参数."
        exit 1
    esac
    exit 0
    

    for/do/done

    oh,这不是python的for in循环么?

    for name in ruhua canglaoshi xiaozhe mihane toshiyuki; do
        if [ "${name}" == "ruhua" ]; then
            echo "I do not like ${name}."
        else
            echo "I like ${name}"
        fi
    done
    #-------------------
    $ ./xm.sh 
    I do not like ruhua.
    I like canglaoshi
    I like xiaozhe
    I like mihane
    I like toshiyuki
    
    # 列出 /home/mark下的所以file
    for fn in "$(ls /home/mark)"; do
        echo "${fn}"
    done
    # 列出当前路径下所有以x开头的文件名
    for fn in x*; do
        echo "${fn}"
    done
    

    while/do/done

    c=1
    while [ "${c}" -lt 3 ]; do
        echo "hi,golang!"
        c=$[${c}+1]
    done
    

    函数

    函数声明

    Shell函数,没有返回值和参数列表

    先定义后调用,调用方式是直接使用函数名

    注意函数体的左花括号'{'和后面的命令之间必须有空格或换行,如果将最后一条命令和右花括号'}'写在同一行,命令末尾必须有;号。

    # 定义函数
    fun(){ echo "Function foo is called";} # {空格echo...;}
    foo(){
        echo "function in shell..."
        echo "$(pwd)"
    }
    # 调用函数
    fun
    foo
    

    函数参数

    Shell函数没有参数列表并不表示不能传参数,事实上,函数就像是迷你脚本,调用函数时可以传任意个参数,在函数内同样是用$0、$1、$2等变量来提取参数,函数中的位置参数相当于函数的局部变量,改变这些变量并不会影响函数外面的$0、$1、$2等变量。函数中可以用return命令返回,如果return后面跟一个数字则表示函数的Exit Status。

    fun1(){
        echo "${0}" # 执行脚本的$0参数
        echo "${1}" # x
        echo "${2}" # y
        echo "${@}" # x,y
        return 0
    }
    
    fun1 x y
    # -----------------
    $ ./xm.sh 
    ./xm.sh
    x
    y
    x y
    

    练习

    # 判断是否是一个目录
    is_directory(){
        # 接收位置参数1
        DIR_NAME="${1}"
        # 是目录 exit status 为0 else 1
        if [ -d "${DIR_NAME}" ]; then
            return 0
        else
            return 1
        fi
    }
    
    # 根据命令行参数创建目录
    for DIR in "${@}"; do
        if is_directory "${DIR}"; then :  # 如果目录已存在 什么也不做 :
        else
            echo "${DIR} doest't exist. Creating it now."
            mkdir "${DIR}" > /dev/null 2>&1 # 创建目录 标准输出 标准错误都重定向到/dev/null 不显示
            if [ $? -ne 0 ]; then # 如果创建目录失败
                echo "Cannot create directory ${DIR}"
                exit 1
            fi
        fi
    done
    
    # for dir in abc def;do
    #     rm -rf ${dir}
    # done
    

    位置参数和特殊变量

    $0  相当于C语言main函数的argv[0]
    $1、$2...    这些称为位置参数(Positional Parameter),相当于C语言main函数的argv[1]、argv[2]...
    $#  相当于C语言main函数的argc - 1,注意这里的#后面不表示注释
    $@  表示参数列表"$1" "$2" ...,例如可以用在for循环中的in后面。
    $*  表示参数列表"$1" "$2" ...,同上
    $?  上一条命令的Exit Status
    $$  当前进程号
    

    位置参数可以用shift命令左移。比如shift 3表示原来的$4现在变成$1,原来的$5现在变成$2等等,原来的$1、$2、$3丢弃,$0不移动。不带参数的shift命令相当于shift 1。例如:

        #! /bin/sh
    
        echo "The program $0 is now running"
        echo "The first parameter is $1"
        echo "The second parameter is $2"
        echo "The parameter list is $@"
        shift
        echo "The first parameter is $1"
        echo "The second parameter is $2"
        echo "The parameter list is $@"
    

    其他

    输入输出

    read V

    echo [option] string
    -e 解析转义字符
    -n 不回车换行。默认情况echo回显的内容后面跟一个回车换行。
    

    文件重定向

    cmd > file             把标准输出重定向到新文件中
    cmd >> file            追加
    cmd > file 2>&1        标准出错也重定向到1所指向的file里
    cmd >> file 2>&1
    cmd < file1 > file2    输入输出都定向到文件里
    cmd < &fd              把文件描述符fd作为标准输入
    cmd > &fd              把文件描述符fd作为标准输出
    cmd < &-               关闭标准输入
    

    tee

    将命令的结果输入到标准输出的同时保存到文件

    tee -a x.txt -a参数表示追加

    cd /home/mark
    ls -alh | tee a.txt
    

    find

    grep

    awk 处理行和列

    sed 处理行

  • 相关阅读:
    Distributed Transaction Coordinator 服务因 3221229584 (0xC0001010) 服务性错误而停止 解决办法
    串行通信
    Sun下山后的IT格局 Oracle能抗衡IBM吗?
    串行通信比并行通信的速度更高
    ERP渠道商怨气冲天 自比“农民工”没有明天
    销售渠道
    甲骨文中国开始整合SUN中国 SUN市场部遭洗牌
    PHP 事件机制(2)
    (备忘)
    jquery键盘事件的更改
  • 原文地址:https://www.cnblogs.com/endurance9/p/10322949.html
Copyright © 2011-2022 走看看