内部变量

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

位置参数

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

强制退出程序本身

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

字符长度

这三种方法都可以取出字符串的长度
${#string}
expr length $string
expr " $string" : ' . * '
实例:如果输入的 id 号小于 6 个字符就告诉用户是非法的 id 号,大于 6 是合法的 id 号
#!/bin/bash
echo -e "please input you id:"
read string
#ln=${#string} #这 句注释掉的和下面的那句起同样的作用
#ln=$( expr "$string" : '.*')
ln=$( expr length $string )
((ln < )) && 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
不要前面 个字符:
[root@oracle ~]# echo ${stringZ:}
123bbb456ccc
从编号为 的字符,即第 个字符开始,提取 个字符
[root@oracle ~]# echo ${stringZ::}
aaa123

函数提取

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

前面提取字符串

• 按照正则表达式从前面开始提取字符串,注意表达式写在\ ( \ )
• 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
/vmlinuz-2.6.-.el6.x86_64
[root@desktop Desktop]# VV=$(cat /boot/grub/grub.conf |grep kernel|grep 2.6
|cut -d ' ' -f )
[root@desktop Desktop]# echo ${VV#/[a-z]*-}
2.6.-.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=$
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 ./
`./.TXT' -> `./2.txt'
`./.TXT' -> `./3.txt'
`./.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 参数

综合练习

实例 :
echo `basename $PWD` # 打印当前工作路径最后一段子目录名字
echo "${PWD##*/}" # 另一种方法的实现
echo `basename $` # 得到脚本的名字
echo $ # 另一种方法的实现
echo "${0##*/}" # 另一种方法的实现
filename=test.data
echo "${filename##*.}" # 移除"."之前的内容,得到 data 文件名的后缀
实例 :
下面的例子实现将特定的文件名后缀,比如 .gif 统统改为其他后缀
for filename in *.$ # 遍历当前整个目录中所有指定的文件后缀
do
mv $filename ${filename%$}$
#去除掉输入的文件名后缀再追加另外指定的一个
done
exit
实例 :
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##*/}; # 同样的效果
实例 :下面的例子将一个用户 yangwawa 主目录的文件拷贝到另一个用户 joe(可以用$代替写在脚本中)的主目录中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[]="Windows 2007"
BOOKS[]="Windows xp"
BOOKS[]="Oracle"
BOOKS[]="IBM ATX 5"
BOOKS[]="RedHat"
echo "${BOOKS[@]}" #将数组作为一串字符打印出来
echo ++++++++++++++++++++++
TOTAL=${#BOOKS[@]} #以空格为依据取字符串的长度
for ((X_B=;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 Windows xp Oracle IBM ATX RedHat
++++++++++++++++++++++
--> Windows
--> Windows xp
--> Oracle
--> IBM ATX
--> RedHat

BASH 编程之变量高级篇的更多相关文章

  1. bash编程-Shell变量

    bash中,所有变量的值默认均为字符串. 1. 变量操作 调用变量 $变量 查看变量(所有类型) set 删除变量 unset 变量 2. 变量分类 2.1 自定义变量 自定义变量仅对当前Shell有 ...

  2. 怎样用 Bash 编程:逻辑操作符和 shell 扩展

    学习逻辑操作符和 shell 扩展,本文是三篇 Bash 编程系列的第二篇. Bash 是一种强大的编程语言,完美契合命令行和 shell 脚本.本系列(三篇文章,基于我的 三集 Linux 自学课程 ...

  3. Bash 脚本编程的一些高级用法

    概述 偶然间发现 man bash 上其实详细讲解了 shell 编程的语法,包括一些很少用却很实用的高级语法.就像发现了宝藏的孩子,兴奋莫名.于是参考man bash,结合自己的理解,整理出了这篇文 ...

  4. 脚本编程中的test、bash调试、变量计算、参数

    脚本编程中的test.bash调试.变量计算.参数 1.文件测试 -e FILE:测试文件是否存在 -f FILE:测试文件是否为普通文件 -d FILE:测试路径是否为目录 -r FILE:测试当前 ...

  5. (十一) 一起学 Unix 环境高级编程 (APUE) 之 高级 IO

    . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...

  6. Kotlin——从无到有系列之高级篇(一):Lambda表达式

    如果您对Kotlin很有兴趣,或者很想学好这门语言,可以关注我的掘金,或者进入我的QQ群大家一起学习.进步. 欢迎各位大佬进群共同研究.探索 QQ群号:497071402 进入正题 经过前面一系列对K ...

  7. 常见 Bash 内置变量介绍

    目录 $0$1, $2 等等$#$* 与 "$*"$@ 与 "$@"$!$_$$$PPID$?$BASH$BASH_VERSION$EUID 与 $UID$GR ...

  8. 大数据系列博客之 --- 深入简出 Shell 脚本语言(高级篇)

    首先声明,此系列shell系列博客分为四篇发布,分别是: 基础篇:https://www.cnblogs.com/lsy131479/p/9914747.html 提升篇:https://www.cn ...

  9. Bash拾遗:变量

    使用引号包裹变量 在<高级Bash脚本编程指南>中的4.1节中有这么个例子: hello="A B C D" echo $hello # A B C D echo &q ...

随机推荐

  1. Python3实用编程技巧进阶 ☝☝☝

    Python3实用编程技巧进阶  ☝☝☝ 1.1.如何在列表中根据条件筛选数据 # 1.1.如何在列表中根据条件筛选数据 data = [-1, 2, 3, -4, 5] #筛选出data列表中大于等 ...

  2. C# 添加、读取、删除Excel文档属性

    在文档属性中,可以设置诸多关于文档的信息,如创建时间.作者.单位.类别.关键词.备注等摘要信息以及一些自定义的文档属性.下面将通过C#程序来演示如何设置,同时对文档内的已有信息,也可以实现读取或删除等 ...

  3. 关于CSS Grid Layout的代码解释

    .wrapper { display: grid; /*生成grid类型块级网格*/ grid-template-columns: repeat(3, 1fr); /*设置显示的列网格线,且重复3次1 ...

  4. ThinkPhp3.1.3执行存储过程返回false

    1.Tp在调用存储过程的时候,每次都显示false 返回一大片,下面是我自己的代码.

  5. DeCantor Expansion (逆康托展开)

    Background\text{Background}Background The \text{The }The Listen&Say Test will be hold on May 11, ...

  6. Git推送到多个远程仓库

    Git推送到多个远程仓库 Grey 原文地址 准备工作 在码云和Github上分别新建两个不包括任何文件的空仓库(若是两个已经有文件的仓库,请参见关联已经存在的项目) https://github.c ...

  7. LeetCode初级算法--设计问题01:Shuffle an Array (打乱数组)

    LeetCode初级算法--设计问题01:Shuffle an Array (打乱数组) 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:h ...

  8. NetworkManager网络通讯_NetworkLobbyManager(三)

    此部分可以先建立游戏大厅,然后进入游戏,此处坑甚多耗费大量时间.国内百度出来的基本没靠谱的,一些专栏作家大V也不过是基本翻译了一下用户手册(坑啊),只能通过看youtube视频以及不停的翻阅用户手册解 ...

  9. PHP通过JSON给JS赋值;JS通过JSON给PHP传值

    $fileNames = array(); // 是数组,不是字符串 $filesJSON = json_encode($fileNames);// 转成json格式 var oldFiles = n ...

  10. 认识JVM的内存分配

    当我们在JVM中运行一段程序代码,JVM初始运行的时候都会分配好Method Area(方法区)和Heap(堆),而JVM每遇到一个线程,就为其分配一个Program Counter Register ...