BASH 编程之变量高级篇

内部变量

• $$与$BASHPID都代表着执行程序的进程 ID,我们可以通过 echo 打印,并用 ps 指令检查得到相同的进程 ID

[[email protected] ~]# echo $BASHPID #没有结果??
[[email protected] ~]# echo $$ #显示执行进程的 id 号
3131
[[email protected] ~]# 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\nusage : $0 canshu1 " && exit -1 || echo "right"
#-n 测试参数的长度是否为 0,不为 0 则返回 0,表示 true
测试:
[[email protected] ~]# ./f2.sh 没有接参数
wrong
usage : ./f2.sh canshu1
[[email protected] ~]# echo $?
255
[[email protected] ~]# ./f2.sh ff 接了参数
right
[[email protected] ~]# echo $?
0

当这些参数在“”之间时:

• $#表示参数数量的总数,也就是总共有多少参数

• $*所有的参数以一行显示

• [email protected]所有的参数以空格分隔

• let 可以对 C语言的表达式做计算,还有另外一种方法实现$((index+=1))

实例:区别以上符号代表的意义

1、$#
#!/bin/bash
in=1
for arg in "$#"
do
echo "arg $in = $arg"
let "in=in+1"
done
测试结果:$#表示参数总数
[[email protected] ~]# ./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
测试:$*参数以一行显示
[[email protected] ~]# ./f1.sh a b c
arg 1 = a b c
3、[email protected]
#!/bin/bash
in=1
for arg in "[email protected]"
do
echo "arg $in = $arg"
$((in+=1))
done
测试:[email protected]参数以空格为分隔
[[email protected] ~]# ./f1.sh a b c
arg 1 = a
arg 2 = b
arg 3 = c

强制退出程序本身

•$!代表进程本身

•eval可以对字符串的代码当成 bash 代码并运行,等同于` `和$( )

•(())中变量无需在变量前使用$,而且没有空格的局限性

[[email protected] ~]# vim &> { sleep 2;
> eval ‘kill -9 $!‘ &> /dev/null;
> }
[1] 3855
#停了 2 秒
[1]+ Stopped vim
You have new mail in /var/spool/mail/root
[[email protected] ~]#
[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‘

[[email protected] Desktop]# num=1234HHHjjj123
[[email protected] Desktop]# echo $num
1234HHHjjj123
[[email protected] Desktop]# echo ${num}
1234HHHjjj123
[[email protected] Desktop]# echo ${#num}

13

[[email protected] Desktop]# echo "${num}kk"

1234HHHjjj123kk

[[email protected] ~]# stringZ=123aaa123bbb456ccc

接下来的 2 句脚本查找的是 123aaa123bbb4 的长度:13

[[email protected] ~]# echo `expr match "$stringZ" ‘123[a-z1-9]*.4‘`

13

[[email protected] ~]# 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} 冒号之间没有空格哦

实例:

[[email protected] ~]# stringZ=123aaa123bbb456ccc
不要前面 6 个字符:
[[email protected] ~]# echo ${stringZ:6}
123bbb456ccc
从编号为 3 的字符,即第 4 个字符开始,提取 6 个字符
[[email protected] ~]# echo ${stringZ:3:6}
aaa123

函数提取

•也可以使用 substr函数提取,注意这个函数索引从 1 开始

•expr substr $string $position $length

[[email protected] ~]# stringZ=123aaa123bbb456ccc
从第 6 个字符即 a 开始提取 6 个字符:
[[email protected] ~]# echo `expr substr $stringZ 6 6`
a123bb

实例:取一个字符串中的日期

[[email protected] Desktop]# SN=WINDD20110908DDSL
[[email protected] Desktop]# echo ${SN:5:4}-${SN:9:2}-${SN:11:2}
2011-09-08

前面提取字符串

• 按照正则表达式从前面开始提取字符串,注意表达式写在\ ( \ )

• expr match "$string"‘\ ( $substring \ ) ‘

• expr " $string" : ‘ \($substring\ ) ‘

实例: stringZ=123aaa123bbb456ccc

[[email protected] ~]# echo `expr match "$stringZ" ‘\(123[a-z]..[1-9]*\)‘`
123aaa123
[[email protected] ~]# echo `expr "$stringZ" : ‘\(123[a-z]..[1-9]*\)‘`
123aaa123

后面提取字符串

•按照正则表达式从后面开始提取字符串,注意表达式写在\ ( \ )

•.*中“.”表示任何字符,“*”表示 0 到无穷的匹配

•expr match "$string" ‘.* \($substring\) ‘

•expr " $string" : ‘.*\($substring\)

实例: stringZ=123aaa123bbb456ccc

[[email protected] ~]# echo `expr "$stringZ" : ‘.*\([a-z]...\)‘`
b456

前面字符串移除

• 按照正则表达式从前面开始移除字符串中的部分

• ${string #substring}仅移除最先匹配的部分

• ${string ##substring}只要是匹配统统移除

实例:[[email protected] ~]# stringQ=qqww20081010aabb

[[email protected] ~]# echo "${stringQ#q*w}" 最短匹配
w20081010aabb
[[email protected] ~]# echo "${stringQ##q*w}" 最长匹配
20081010aabb

实例:找出内核版本号

[[email protected] Desktop]# cat /boot/grub/grub.conf |grep kernel|grep 2.6 |cut
-d ‘ ‘ -f 2
/vmlinuz-2.6.32-71.el6.x86_64
[[email protected] Desktop]# VV=$(cat /boot/grub/grub.conf |grep kernel|grep 2.6
|cut -d ‘ ‘ -f 2)
[[email protected] Desktop]# echo ${VV#/[a-z]*-}
2.6.32-71.el6.x86_64

后面字符串移除

• 按照正则表达式从后面开始移除字符串中的部分

•${string%substring}仅移除从后面开始最先匹配的部分

•${string%%substring}只要是匹配统统移除

实例:[[email protected] ~]# stringQ=qqww20081010aabb

[[email protected] ~]# echo "${stringQ%0*b}" 从后面最短匹配
qqww2008101
[[email protected] ~]# 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
测试:
[[email protected] 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 声明了,只是没有设置参数
[[email protected] Desktop]# N=
[[email protected] Desktop]# N1=qq
[[email protected] Desktop]# echo "${N-dd}" 没有设置参数的 N 没被替换
You have new mail in /var/spool/mail/root
[[email protected] Desktop]# echo "${N:-dd}" 没有设置参数的 N 被替换
dd
[[email protected] Desktop]# echo "${N1-dd}" 设置了参数的 N1 没被替换
qq
[[email protected] Desktop]# echo "${N1:-dd}" 设置了参数的 N1 没被替换
qq
没有声明的 N2,被默认值替换
[[email protected] Desktop]# echo "${N2-dd}"
dd
[[email protected] 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

[[email protected] Desktop]# M=
[[email protected] Desktop]# M1=rr
[[email protected] Desktop]# echo "${M=aa}"
[[email protected] Desktop]# echo "${M:=aa}"
aa
[[email protected] Desktop]# echo "${M1=aa}"
rr
[[email protected] Desktop]# echo "${M1:=aa}"
rr
[[email protected] Desktop]# echo "${M2=aa}"
aa
[[email protected] 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

[[email protected] Desktop]# H=
[[email protected] Desktop]# H1=oo
[[email protected] Desktop]# echo "${H+yy}"
yy
[[email protected] Desktop]# echo "${H:+yy}"
[[email protected] Desktop]# echo "${H1+yy}"
yy
[[email protected] Desktop]# echo "${H1:+yy}"
yy
[[email protected] Desktop]# echo "${H2+yy}"
[[email protected] 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}}
提取目录中的文件名:
[[email protected] Desktop]# FILENAME=/etc/sysconfig/network-scripts/ifcfg-eth0
[[email protected] Desktop]# basename $FILENAME
ifcfg-eth0
[[email protected] Desktop]# echo ${FILENAME##*/}
ifcfg-eth0
[[email protected] Desktop]# echo ${FILENAME%/*}
/etc/sysconfig/network-scripts
拼接目录:
[[email protected] Desktop]# BACK_DIR=/usr/local/share
[[email protected] Desktop]# echo $BACK_DIR/${FILENAME##*/}
/usr/local/share/ifcfg-eth0
替换文件路径中目录的名字:
[[email protected] Desktop]# FILENAME=/home/student/.mozilla/firefox/profiles.ini
[[email protected] 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
测试:
[[email protected] Desktop]# chmod u+x showbooks.sh
[[email protected] 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

原文地址:https://www.cnblogs.com/zoujiaojiao/p/10938328.html

时间: 2024-10-12 08:19:41

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

bash编程之变量替换

${var#*word}:表示以word为$VAR的分隔符,从左至右,找到第一次匹配的分隔符以后,去掉分隔符(含分隔符)左侧的所有字符 ${var##*word}:表示以word为$VAR的分隔符,从左至右,找到最后一次匹配的分隔符以后,去掉分隔符(含分隔符)左侧的所有字符 ${var%word*}:表示以word为$VAR的分隔符,从右至左,找到第一次匹配的分隔符以后,去掉分隔符(含分隔符)右侧的所有字符 ${var%%word*}:表示以word为$VAR的分隔符,从右至左,找到最后一次匹配

Linux下Bash编程之变量详解(一)

1.语言分类: 1.1.静态语言:编译型语言 强类型:变量在使用前,必须事先声明,甚至还需要初始化: 编写的程序事先转换成可执行格式 代表有:C.C++.JAVA.C# 动态语言:解释型语言 弱类型:变量用时声明,甚至不区分类型: 编写的程序边解释边执行 代表有: PHP.SHELL.python.perl 1.2.面向过程编程语言:代表有 Shell, C 1.3.面向对象编程语言: 代表有 JAVA, Python, perl, C++ 结论:shell属于弱类型编程语言 2.shell编程

Bash编程中变量有无双引号探秘

对于一般的变量,有无双引号效果是一样的,如下所示: $ sport="marathon" $ echo $sport marathon $ echo "$sport" marathon 那么,对于二般的变量,就有差别了,如下: $ cat sports.txt walking running swimming singing drawing dancing basketball volleyball soccer $ sports=$(cat sports.txt)

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

学习逻辑操作符和 shell 扩展,本文是三篇 Bash 编程系列的第二篇. Bash 是一种强大的编程语言,完美契合命令行和 shell 脚本.本系列(三篇文章,基于我的 三集 Linux 自学课程)讲解如何在 CLI 使用 Bash 编程. 第一篇文章 讲解了 Bash 的一些简单命令行操作,包括如何使用变量和控制操作符.第二篇文章探讨文件.字符串.数字等类型和各种各样在执行流中提供控制逻辑的的逻辑运算符,还有 Bash 中的各类 shell 扩展.本系列第三篇也是最后一篇文章,将会探索能重

bash编程基础及for循环

bash编程要点 变量: 本地变量:只对当前shell进程有效,对当前shell之外的其它shell(包括其父.子等)无效: 环境变量:对当shell进程及其子shell进程有效: 局部变量:仅在当前shell进程中的某段代码空间内有效:通常用于函数本地程序: 位置变量:$1, $2, ... $1 是传递给该shell脚本的第一个参数 $2 是传递给该shell脚本的第二个参数- 特殊变量: $# 是传给脚本的参数个数 $0 是脚本本身的名字 [email protected] 是传给脚本的所

shell脚本编程高级篇

SHELL脚本编程进阶循环执行:简单来说就是把一些指令重复循环. 循环代码具体的指令有三种: for , while , until其中for, while用的最多.for循环 for 变量名 in 列表;do 循环体 done 关键字的帮助都是用help来查询.for循环语法:在shell编程中 for,in,do,done.这些都是他的关键字,其中循环的指零就放在do和done之间.WORDS决定了循环次数.循环的次数由in 后面跟的WORDS(字符串)的数量决定.字符串的个数决定了do和d

Java 编程之美:并发极速赛车平台出租编程高级篇

借用 Java 并发极速赛车平台出租haozbbs.comQ1446595067 编程实践中的话:编写正确的程序并不容易,而编写正常的并发程序就更难了. 相比于顺序执行的情况,多线程的线程安全问题是微妙而且出乎意料的,因为在没有进行适当同步的情况下多线程中各个操作的顺序是不可预期的. 并发编程相比 Java 中其他知识点学习起来门槛相对较高,学习起来比较费劲,从而导致很多人望而却步: 而无论是职场面试和高并发高流量的系统的实现却都还离不开并发编程,从而导致能够真正掌握并发编程的人才成为市场比较迫

bash脚本编程之变量、变量类型、条件测试、算术运算、及特殊变量

一.学习目的 1.了解bash脚本的变量类型及变量的使用 2.了解bash中条件测试的种类及如何在bash中实现条件的判断 3.学会在bash中做算术运算 4.了解特殊变量的使用 二.学习内容 1). ①.bash的变量类型: 环境变量 .本地变量.局部变量.位置变量.特殊变量 环境变量: export VALUENAME = VALUE 作用领域是当前的shell进程及其子进程 本地变量: VALUENAME= VALUE 作用领域为整个bash的进程 局部变量:local VALUENAME

《C#网络编程高级篇之网页游戏辅助程序设计(扫描版)》

<C#网络编程高级篇之网页游戏辅助程序设计>通过编写C#网络编程语言中具有代表性的实例,向读者深入细致地讲解了如何利用C#语言进行网页游戏辅助程序设计.本书通过大量的代码引导读者一步步学习和掌握C#的网络应用编程的方法和网页游戏辅助程序的设计技术. <C#网络编程高级篇之网页游戏辅助程序设计>涉及的领域包括多线程编程技术.socket套接字编程.tcp协议编程.http协议编程.远程控制技术.木马技术.模拟键盘和鼠标技术.网页游戏辅助程序设计技术等. <C#网络编程高级篇之网