zoukankan      html  css  js  c++  java
  • BASH 编程之变量高级篇

    内部变量

    • $$与$BASHPID都代表着执行程序的进程 ID,我们可以通过 echo 打印,并用 ps 指令检查得到相同的进程 ID
    [root@oracle ~]# echo $BASHPID #没有结果??
    [root@oracle ~]# echo $$ #显示执行进程的 id3131
    [root@oracle ~]# ps ax | grep bash
    2589 ? Ss 0:00 /usr/bin/ssh-agent /bin/sh -c exec -l /bin/bash -c
    "/usr/bin/dbus-launch --exit-with-session /etc/X11/xinit/Xclients"
    2780 pts/1 Ss+ 0:00 bash
    3041 ? S 0:00 /bin/bash /usr/bin/eio
    3131 pts/2 Ss 0:00 bash
    3161 pts/2 R+ 0:00 grep bash

    位置参数

    我们经常向一个程序传递以空格间隔的参数,我们按先后次序分成$0(脚本本身) ,$1(参数 1),$2(参数 2).....
    实例:如果没有输入参数则提示错误并显示用法,返回-1 值;输入了就说明对了,返回 0
    #!/bin/bash
    [ ! -n "$1" ] && echo -e "wrong
    usage : $0 canshu1 " && exit -1 || echo "right"
    #-n 测试参数的长度是否为 0,不为 0 则返回 0,表示 true
    测试:
    [root@oracle ~]# ./f2.sh 没有接参数
    wrong
    usage : ./f2.sh canshu1
    [root@oracle ~]# echo $?
    255
    [root@oracle ~]# ./f2.sh ff 接了参数
    right
    [root@oracle ~]# echo $?
    0
    当这些参数在“”之间时:
    • $#表示参数数量的总数,也就是总共有多少参数
    • $*所有的参数以一行显示
    • $@所有的参数以空格分隔
    • let 可以对 C语言的表达式做计算,还有另外一种方法实现$((index+=1))
    实例:区别以上符号代表的意义
    1、$#
    #!/bin/bash
    in=1
    for arg in "$#"
    do
    echo "arg $in = $arg"
    let "in=in+1"
    done
    测试结果:$#表示参数总数
    [root@oracle ~]# ./f1.sh a b c
    arg 1 = 3
    2、$*
    #!/bin/bash
    in=1
    for arg in "$*"
    do
    echo "arg $in = $arg"
    let "in=in+1"
    done
    测试:$*参数以一行显示
    [root@oracle ~]# ./f1.sh a b c
    arg 1 = a b c
    3、$@
    #!/bin/bash
    in=1
    for arg in "$@"
    do
    echo "arg $in = $arg"
    $((in+=1))
    done
    测试:$@参数以空格为分隔
    [root@oracle ~]# ./f1.sh a b c
    arg 1 = a
    arg 2 = b
    arg 3 = c

    强制退出程序本身

    •$!代表进程本身
    •eval可以对字符串的代码当成 bash 代码并运行,等同于` `和$( )
    •(())中变量无需在变量前使用$,而且没有空格的局限性
    [root@oracle ~]# vim &
    > { sleep 2;
    > eval 'kill -9 $!' &> /dev/null;
    > }
    [1] 3855
    #停了 2 秒
    [1]+ Stopped vim
    You have new mail in /var/spool/mail/root
    [root@oracle ~]#
    [1]+ 已杀死 vim

    字符长度

    这三种方法都可以取出字符串的长度
    ${#string}
    expr length $string
    expr " $string" : ' . * '
    实例:如果输入的 id 号小于 6 个字符就告诉用户是非法的 id 号,大于 6 是合法的 id 号
    #!/bin/bash
    echo -e "please input you id:"
    read string
    #ln=${#string} #这 2 句注释掉的和下面的那句起同样的作用
    #ln=$( expr "$string" : '.*')
    ln=$( expr length $string )
    ((ln < 6)) && echo "$string shi fei fa de id hao" || echo " id $string shi he fa de "

    表达式方式取长度

    •依据正则表达式取得相匹配部分的长度,注意表达式要用单引号
    • expr match "$string"' $substring '
    • expr " $string" : ' $substring'
    [root@desktop Desktop]# num=1234HHHjjj123
    [root@desktop Desktop]# echo $num
    1234HHHjjj123
    [root@desktop Desktop]# echo ${num}
    1234HHHjjj123
    [root@desktop Desktop]# echo ${#num}
    13
    [root@desktop Desktop]# echo "${num}kk"
    1234HHHjjj123kk
    [root@oracle ~]# stringZ=123aaa123bbb456ccc
    接下来的 2 句脚本查找的是 123aaa123bbb4 的长度:13
    [root@oracle ~]# echo `expr match "$stringZ" '123[a-z1-9]*.4'`
    13
    [root@oracle ~]# echo `expr "$stringZ" : '123[a-z1-9]*.4'`
    13
    123[a-z1-9]*.4:必须从字符串的开始字符匹配,[a-z1-9]表示字母 a-z和数字1-9,
    *.4 表示这些字符出现任意次后以 4 结尾

    符号提取

    • 根据字符的位置提取字符串中一段,注意此方法索引由 0 开始
    • ${string:position} 是从 0 开始的哦
    • ${string:position : length} 冒号之间没有空格哦
    实例:
    [root@oracle ~]# stringZ=123aaa123bbb456ccc
    不要前面 6 个字符:
    [root@oracle ~]# echo ${stringZ:6}
    123bbb456ccc
    从编号为 3 的字符,即第 4 个字符开始,提取 6 个字符
    [root@oracle ~]# echo ${stringZ:3:6}
    aaa123

    函数提取

    •也可以使用 substr函数提取,注意这个函数索引从 1 开始
    •expr substr $string $position $length
    [root@oracle ~]# stringZ=123aaa123bbb456ccc
    从第 6 个字符即 a 开始提取 6 个字符:
    [root@oracle ~]# echo `expr substr $stringZ 6 6`
    a123bb
    实例:取一个字符串中的日期
    [root@desktop Desktop]# SN=WINDD20110908DDSL
    [root@desktop Desktop]# echo ${SN:5:4}-${SN:9:2}-${SN:11:2}
    2011-09-08

    前面提取字符串

    • 按照正则表达式从前面开始提取字符串,注意表达式写在 ( )
    • expr match "$string"' ( $substring ) '
    • expr " $string" : ' ($substring ) '
    实例: stringZ=123aaa123bbb456ccc
    [root@oracle ~]# echo `expr match "$stringZ" '(123[a-z]..[1-9]*)'`
    123aaa123
    [root@oracle ~]# echo `expr "$stringZ" : '(123[a-z]..[1-9]*)'`
    123aaa123

    后面提取字符串

    •按照正则表达式从后面开始提取字符串,注意表达式写在 ( )
    •.*中“.”表示任何字符,“*”表示 0 到无穷的匹配
    •expr match "$string" '.* ($substring) '
    •expr " $string" : '.*($substring)
    实例: stringZ=123aaa123bbb456ccc
    [root@oracle ~]# echo `expr "$stringZ" : '.*([a-z]...)'`
    b456

    前面字符串移除

    • 按照正则表达式从前面开始移除字符串中的部分
    • ${string #substring}仅移除最先匹配的部分
    • ${string ##substring}只要是匹配统统移除
    实例:[root@oracle ~]# stringQ=qqww20081010aabb
    [root@oracle ~]# echo "${stringQ#q*w}" 最短匹配
    w20081010aabb
    [root@oracle ~]# echo "${stringQ##q*w}" 最长匹配
    20081010aabb
    实例:找出内核版本号
    [root@desktop Desktop]# cat /boot/grub/grub.conf |grep kernel|grep 2.6 |cut
    -d ' ' -f 2
    /vmlinuz-2.6.32-71.el6.x86_64
    [root@desktop Desktop]# VV=$(cat /boot/grub/grub.conf |grep kernel|grep 2.6
    |cut -d ' ' -f 2)
    [root@desktop Desktop]# echo ${VV#/[a-z]*-}
    2.6.32-71.el6.x86_64

    后面字符串移除

    • 按照正则表达式从后面开始移除字符串中的部分
    •${string%substring}仅移除从后面开始最先匹配的部分
    •${string%%substring}只要是匹配统统移除
    实例:[root@oracle ~]# stringQ=qqww20081010aabb
    [root@oracle ~]# echo "${stringQ%0*b}" 从后面最短匹配
    qqww2008101
    [root@oracle ~]# echo "${stringQ%%0*b}" 从后面最长匹配
    qqww2
    练习:重命名所有在/roo/Desktop 下非 txt 后缀的文件,将其变成"txt"后缀比如"file1.TXT"将变成" file.txt" ...,这个可以很好的解决 windows 文件拷入到 Linux 中的问题
    #!/bin/bash
    DIR=$1
    fix="TXT txT tXt tXT Txt TXt TxT"
    for LINE in $fix
    do
    old=$LINE
    new=txt
    for FILE in $(find $DIR -name "*.$old")
    do
    mv -v $FILE ${FILE%$old}$new
    done
    done
    测试:
    [root@desktop Desktop]# ./chname.sh ./
    `./2.TXT' -> `./2.txt'
    `./3.TXT' -> `./3.txt'
    `./1.TXT' -> `./1.txt'

    表达式方式字符串替换

    • 有点雷同与 sed 的表达式
    • ${string / substring /replacement}首先匹配的被替换
    • ${string/ /substring/replacement}匹配的全部替换
    •从前面很多的例子中我们可以看到在${}中“#”代表从前面,“ %”代表从后面,因此
    ${string/#substring / replacement}从前面查找并替换;
    ${string /%substring / replacement}从后面查找并替换

    参数替换

    •${parameter}与直接使用$parameter 相同,但在很多的情况下使用${}可以减少歧义。
    •${parameter-default} , ${parameter: -default}
    •如果参数没有设置,将使用默认值
    N 声明了,只是没有设置参数
    [root@desktop Desktop]# N=
    [root@desktop Desktop]# N1=qq
    [root@desktop Desktop]# echo "${N-dd}" 没有设置参数的 N 没被替换
    You have new mail in /var/spool/mail/root
    [root@desktop Desktop]# echo "${N:-dd}" 没有设置参数的 N 被替换
    dd
    [root@desktop Desktop]# echo "${N1-dd}" 设置了参数的 N1 没被替换
    qq
    [root@desktop Desktop]# echo "${N1:-dd}" 设置了参数的 N1 没被替换
    qq
    没有声明的 N2,被默认值替换
    [root@desktop Desktop]# echo "${N2-dd}"
    dd
    [root@desktop Desktop]# echo "${N2:-dd}"
    dd
    DEFAULT_FILENAME=generic.data
    filename = ${1:-$DEFAULT_FILENAME}
    以上两句等同于下面的一段代码
    # 如果位置第一个位置参数长度为 0( 没有设置$1)
    if [ ! -n $1 ]
    # 那么
    then
    #filename 设置为缺省的值
    filename=gerneric.data fi
    •下面的表达式与之前的表达式雷同,细微的不同的${parameter -default}只判断参数是 否已经设置${parameter = default} ,${parameter:=default} 如果参数已经设置,但为空,将使用缺省值 echo ${username=`whoami`} 此处,之前没有定义过 username,那么变量将设置为`whoami`命令的结果
    if [ -n $username ]; then
    username=$username
    else
    username=`whoami`
    fi
    [root@desktop Desktop]# M=
    [root@desktop Desktop]# M1=rr
    [root@desktop Desktop]# echo "${M=aa}"
    [root@desktop Desktop]# echo "${M:=aa}"
    aa
    [root@desktop Desktop]# echo "${M1=aa}"
    rr
    [root@desktop Desktop]# echo "${M1:=aa}"
    rr
    [root@desktop Desktop]# echo "${M2=aa}"
    aa
    [root@desktop Desktop]# echo "${M2:=aa}"
    aa
    •如果参数设置了,使用替换值,否则清空变量${parameter+alt} ,${parameter:+alt} 逻辑等同于:
    if [ -n $parameter ]
    then
    parameter=$alt
    else
    # 清空此参数
    parameter=
    fi
    例子:
    a=${param1+xyz} # 由于 param1 没有设置所以 a 为空
    echo "a = $a" # a =
    param2= # param2 设置为空
    a=${param2+xyz}
    echo "a = $a" # 有设置将替换成缺省值 a = xyz
    param3=123 # param3 设置为 123
    a=${param3+xyz}
    echo "a = $a" # 有设置将替换成缺省值 a = xyz
    [root@desktop Desktop]# H=
    [root@desktop Desktop]# H1=oo
    [root@desktop Desktop]# echo "${H+yy}"
    yy
    [root@desktop Desktop]# echo "${H:+yy}"
    [root@desktop Desktop]# echo "${H1+yy}"
    yy
    [root@desktop Desktop]# echo "${H1:+yy}"
    yy
    [root@desktop Desktop]# echo "${H2+yy}"
    [root@desktop Desktop]# echo "${H2:+yy}"

    错误检测

    •判断参数是否设置,没有将打印后面的错误信息,${parameter ? error_msg}, $
    {parameter :? error_msg}
    •下面的例子可以直接对系统变量检查,如果没有设置,将直接退出程序
    ${HOSTNAME?} ${USER?} ${HOME?} ${MAILBOX ?}
    :${ZZXy23AB ? "ZZXy23ABhasnotbeenset"}
    ${1 ? "Usage:$0 x.x.x.x"}# 最为简单的方式检查是否设置位置 1 参数

    综合练习

    实例 1:
    echo `basename $PWD` # 打印当前工作路径最后一段子目录名字
    echo "${PWD##*/}" # 另一种方法的实现
    echo `basename $0` # 得到脚本的名字
    echo $0 # 另一种方法的实现
    echo "${0##*/}" # 另一种方法的实现
    filename=test.data
    echo "${filename##*.}" # 移除"."之前的内容,得到 data 文件名的后缀
    实例 2:
    下面的例子实现将特定的文件名后缀,比如 .gif 统统改为其他后缀
    for filename in *.$1 # 遍历当前整个目录中所有指定的文件后缀
    do
    mv $filename ${filename%$1}$2
    #去除掉输入的文件名后缀再追加另外指定的一个
    done
    exit 0
    实例 3:
    path_name=/home/bozo/ideas/thoughts.for.today
    echo "path_name = $path_name"
    t=${path_name##/*/} # 根据表达式最大可能的移除/部分,最后只留下文件名
    echo "path_name, stripped of prefixes = $t"
    t=${path_name%/} ; t=${t##*/}; # 同样的效果
    实例 4:下面的例子将一个用户 yangwawa 主目录的文件拷贝到另一个用户 joe(可以用$1代替写在脚本中)的主目录中FILENAME=/home/yangwawa/.bash_profile
    cp -v $FILENAME{,${FILENAME/yangwawa/joe}}
    提取目录中的文件名:
    [root@desktop Desktop]# FILENAME=/etc/sysconfig/network-scripts/ifcfg-eth0
    [root@desktop Desktop]# basename $FILENAME
    ifcfg-eth0
    [root@desktop Desktop]# echo ${FILENAME##*/}
    ifcfg-eth0
    [root@desktop Desktop]# echo ${FILENAME%/*}
    /etc/sysconfig/network-scripts
    拼接目录:
    [root@desktop Desktop]# BACK_DIR=/usr/local/share
    [root@desktop Desktop]# echo $BACK_DIR/${FILENAME##*/}
    /usr/local/share/ifcfg-eth0
    替换文件路径中目录的名字:
    [root@desktop Desktop]# FILENAME=/home/student/.mozilla/firefox/profiles.ini
    [root@desktop Desktop]# echo ${FILENAME/student/visitor}
    /home/visitor/.mozilla/firefox/profiles.ini

    定义一个变量

    declare -r 定义一个只读变量
    declare -i 定义的变量是一个数字,对于数字变量可以不用在变量名前使用"$"符号
    declare -a 定义的是数组
    declare -f 定义的是函数
    declare -x 定义的变量在 bash 中等同于 export 可以为其他程序所用

    declare 显示变量

    • declare 命令对于标识变量也非常有用
    bash$ declare | grep HOME
    /home/bozo
    bash$ zzy=68
    bash$ declare | grep zzy
    zzy=68
    bash$ Colors=([0]="purple" [1]="reddish-orange" [2]="light green")
    bash$ echo ${Colors[@]}
    purple reddish-orange light green
    bash$ declare | grep Colors
    Colors=([0]="purple" [1]="reddish-orange"[2]="light green")

    数组概述

    • 申明 数组
    declare - aarray
    array[xx]
    • 调用 时
    ${array[ xx] }

    数组使用

    打印书名:
    #!/bin/bash
    declare -a BOOKS
    BOOKS[0]="Windows 2007"
    BOOKS[1]="Windows xp"
    BOOKS[2]="Oracle"
    BOOKS[3]="IBM ATX 5"
    BOOKS[4]="RedHat"
    echo "${BOOKS[@]}" #将数组作为一串字符打印出来
    echo ++++++++++++++++++++++
    TOTAL=${#BOOKS[@]} #以空格为依据取字符串的长度
    for ((X_B=0;X_B<TOTAL;X_B++))
    do
    echo "$X_B --> ${BOOKS[$X_B]}"
    done
    测试:
    [root@desktop Desktop]# chmod u+x showbooks.sh
    [root@desktop Desktop]# ./showbooks.sh
    Windows 2007 Windows xp Oracle IBM ATX 5 RedHat
    ++++++++++++++++++++++
    0 --> Windows 2007
    1 --> Windows xp
    2 --> Oracle
    3 --> IBM ATX 5
    4 --> RedHat
  • 相关阅读:
    需求征集系统第四天
    EL表达式和JSTL
    需求征集系统第三天
    [2019.1.6]BZOJ4197 [Noi2015]寿司晚宴
    [2019.1.7]BZOJ1011 [HNOI2008]遥远的行星
    [2019.1.3]BZOJ4326 NOIP2015 运输计划
    [2019.1.2]BZOJ2115 [Wc2011] Xor
    [2019.1.2]BZOJ2460 [BeiJing2011]元素
    [2019.1.1]BZOJ1806 [Ioi2007]Miners 矿工配餐
    [2019.1.1]BZOJ4195 [Noi2015]程序自动分析
  • 原文地址:https://www.cnblogs.com/zoujiaojiao/p/10938328.html
Copyright © 2011-2022 走看看