您的位置:首页 > 运维架构 > Shell

Shell脚本学习指南(二)——变量、条件、循环

2016-05-13 18:00 736 查看

变量

基本概念

Shell变量的名称与C语言一样,由数字、字母、下划线组成,其中只能以字母或下划线开头

变量可以为空值,null

赋值时,=两边没有空格

str="abc"
a=1


取变量的值时,在变量前面加$

a=1
echo $a => 1


变量的值如果含空格,赋值时用双引号括起来

str="Hello World!"


算数展开 $( (…) )

i=5 j=6
echo $((i+j))             => 11
echo $(((i*j)-(i+j)))     => 19
echo $((3>1))             => 1
echo $((1>3))             => 0


相关命令

export:将shell变量输出为环境变量,或者将shell函数输出为环境变量

打印当前环境变量

export      => 打印当前进程的所有环境变量
export -p   => 同export


修改当前进程的环境变量

export DAVID="david"           => 设置环境变量DAVID,值为david
export PATH=$PATH:/home/david  => 在PATH后面追加/home/david路径


readonly:定义只读shell变量和shell函数

打印当前只读变量

readonly      => 打印当前进程的所有只读变量
readonly -p   => 同readonly


设置当前进程的只读变量

readonly DAVID="david"           => 设置只读变量DAVID,值为david


env:为将要运行的程序设置环境变量

-i

env -i A=1 B=2 awk 'xxx' file   # 用新的环境变量重新初始化环境变量,然后运行命令
# 新环境变量只对将要运行的命令生效


-u

env -u xxx awk 'xxx' file       # 删除某个环境变量,然后用新的环境变量运行命令
# 新环境变量只对将要运行的命令生效


set:更改shell特性

-x 显示执行的语句

+x 不显示执行的语句

unset:删除已经定义的变量或函数

-f 删除函数

-v 删除变量

参数展开

:如果变量前后需要连接其他字符串,则用{}展开

str="Hello World!"
echo __$str__    => __
echo __${str}__  => __Hello World!__


未定义的变量会展开为null字符串

# 非常危险!

rm -fr /$UnDeclareVar   => rm -fr /


替换运算符

${varname:-word}

实现:如果varname存在且非null,则返回其值;否则返回word

用途:如果变量未定义,则返回一个默认值

str1="Hello Shell!"
echo ${str1:-Default} => Hello Shell!
echo ${str2:-Default} => Default


${varname:=word}

实现:如果varname存在且非null,则返回其值;否则设置varname=word,并返回varname

用途:如果变量未定义,则将变量设为默认值并返回该变量

str1="Hello Shell!"
echo ${str1:=Default} => Hello Shell!
echo ${str2:=Default} => Default
echo $str2            => Default


${varname:?message}

实现:

如果varname存在且非null,则返回其值;否则显示varname:message,并退出脚本
如果省略message,显示默认信息"parameter null or not set"
注:交互式Shell下不需要退出,不同Shell有不同行为


用途:捕捉由于变量未定义而导致的错误

str1="Hello Shell!"
echo ${str1:?str1 is not set} => Hello Shell!
echo ${str2:?str2 is not set} => line N: str2: str2 is not set
echo ${str2:?}                => line N: str2: parameter null or not set


${varname:+word}

实现:如果varname存在且非null,则返回word;否则返回null

用途:测试变量是否存在

str1="Hello Shell!"
echo ${str1:+1} => 1
echo ${str2:+1} => (null)


以上四种替换运算符,” : “都是可选的。如果省略” : “,则只判断是否存在,不判断是否非空

替换运算符用途实现
${varname:-word}如果变量未定义,则返回一个默认值如果varname存在且非null,则返回其值;否则返回word
${varname:=word}如果变量未定义,则将变量设为默认值并返回该变量如果varname存在且非null,则返回其值;否则设置varname=word,并返回varname
${varname:?msg}捕捉由于变量未定义而导致的错误如果varname存在且非null,则返回其值;否则显示varname:message,并退出脚本;如果省略message,显示默认信息”parameter null or not set”
${varname:+word}测试变量是否存在如果varname存在且非null,则返回word;否则返回null
${varname:-word}如果变量未定义,则返回一个默认值如果varname存在,则返回其值;否则返回word
${varname:=word}如果变量未定义,则将变量设为默认值并返回该变量如果varname存在,则返回其值;否则设置varname=word,并返回varname
${varname:?msg}捕捉由于变量未定义而导致的错误如果varname存在,则返回其值;否则显示varname:message,并退出脚本;如果省略message,显示默认信息”parameter null or not set”
${varname:+word}测试变量是否存在如果varname存在,则返回word;否则返回null
模式匹配运算符

${varname#pattern}

如果模式匹配与变量的开头处,则删除匹配的最短部分,并返回剩下的部分

${varname##pattern}

如果模式匹配与变量的开头处,则删除匹配的最长部分,并返回剩下的部分

${varname%pattern}

如果模式匹配与变量的结尾处,则删除匹配的最短部分,并返回剩下的部分

${varname%%pattern}

如果模式匹配与变量的结尾处,则删除匹配的最长部分,并返回剩下的部分

str1="/home/davidwang/test/home/test.tar.bz"
echo ${str1#/*/}   => davidwang/test/home/test.tar.bz
echo ${str1##/*/}  => test.tar.bz
echo ${str1%.*}    => /home/davidwang/test/home/test.tar
echo ${str1%%.*}   => /home/davidwang/test/home/test


字符串长度运算符

${#var}

str="abcdefghijklmnopqrstuvwxyz"
echo "$str size is ${#str}"  => abcdefghijklmnopqrstuvwxyz size is 26


位置参数

N:某个命令行参数,从1开始算,如果N>9,则用花括号括起来{10}

$#:命令行参数的个数

∗,@:一次表示所有参数

“$*”:将所有参数当做一个字符串

“$@”:将所有参数视为单独的个体

echo "\$1 = ${1:-/dev/null}"
./test.sh       => $1 = /dev/null
./test.sh 1 2 3 => $1 = 1

echo "arg num = $#"
echo "\$* = $*"
echo "\$@ = $@"
printf "\"\$*\" = %s\n" "$*"
printf "\"\$@\" = %s\n" "$@"

./test.sh 1 2 3 ==>
arg num = 3
$* = 1 2 3
$@ = 1 2 3
"$*" = 1 2 3
"$@" = 1
"$@" = 2
"$@" = 3


特殊变量

变量意义
0Shell程序名称
#参数个数
@命令行参数,如果在”“内,则展开为一系列单独的参数
*命令行参数,如果在”“内,则把所有参数合并为一个字符串
$当前进程ID
PPID父进程ID
?前一个命令的退出状态
!最近一个后台命令的进程编号
HOME用户根目录
PATH命令的查找路径
PWD当前工作目录
LINENO行号
-传给Shell的选项
PS1主要的命令提示字符串;默认为$
PS2行继续的提示字符串;默认为>
PS4以set -x设置的执行跟踪的提示字符串;默认为+
LANG当前local默认名称;其他LC_*变量会覆盖其值
LC_ALL当前local名称;会覆盖LANG和其他LC_*变量
LC_COLLATE用来排序字符的当前local名称
LC_CTYPE在模式匹配期间,用来确定字符类别的当前local名称
LC_MESSAGES输出信息的当前语言的名称
ENV仅用于交互式Shell;要读取和在启动时要执行的一个文件的完整路径名;XSI必须的变量
IFS内部的字段分隔器
NLSPATH在$LC_MESSAGES(XSI)所给定的信息语言里,信息目录的位置

条件

退出状态

每一条命令,不管是内置的还是外部的,退出时均返回一个整数值

0表示成功,非0表示失败,用$?访问

exit命令:传递一个退出值给调用者;如果没有提供退出值,默认为最后一个命令的退出状态

if语句

if [[ condition ]]; then
#statements
elif [[ condition ]]; then
#statements
else
#statements
fi


test命令

两种形式

str1="abc"
str2="abc"

if test $str1 = $str2; then
echo "str1 == str2"
else
echo "str1 != str2"
fi

# 下面的形式等同于上面的形式

if [[ $str1 = $str2 ]]; then
echo "str1 == str2"
else
echo "str1 != str2"
fi


运算符

运算符如果…则为真
-e filefile存在
-s filefile不为空
-f filefile是一般文件
-d filefile是目录
-b filefile是块设备文件
-c filefile是字符设备文件
-p filefile是命名管道(FIFO)
-S filefile是socket
-h filefile是符号链接
-L filefile是符号链接,同-h
-r filefile是可读的
-w filefile是可写入的
-x filefile是可执行的,或file是可被查找的目录
-g filefile有设置setgid位
-u filefile有设置setuid位
stringstring不是null
-n stringstring非null
-z stringstring是null
s1 = s2字符串s1等于s2
s1 != s2字符串s1不等于s2
n1 -eq n2整数n1等于n2
n1 -ne n2整数n1不等于n2
n1 -lt n2整数n1小于n2
n1 -gt n2整数n1大于于n2
n1 -le n2整数n1小于等于n2
n1 -ge n2整数n1大于等于n2
-t n文件描述符n指向以终端
# 在test中,所有变量展开都需要用引号括起来

if[ -f "$file" ]  ==> 正确
if[ -f $file ]    ==> 如果$file为空,shell的行为无法预料


case语句

case word in
pattern )
;;      # 执行到;;结束
* )         # 默认动作,相当于C语言中的default
;;
esac


循环

for语句

for i in words; do
#statements
done

for i; do   #相当于for i in "$@"
#statements
done

for (( i = 0; i < 10; i++ )); do
#statements
done


while与until语句

while [[ condition ]]; do # condition为真时执行
#statements
done

until [[ condition ]]; do # condition为假时执行
#statements
done


break与continue

break:跳出循环

continue 继续执行下一个循环

break与continue,都可以接受数值参数,控制语句跳出或继续执行多少个循环

while [[ condition ]]; do
while [[ condition ]]; do
#statements
break 2  # 跳出最外面的循环
done
done


shift

依次处理命令行参数

每次执行后,原来的1消失,用2的旧值取代,2的新值被3的旧值取代…,$#也会依次减1

有一个可选参数,指定每一次移动几位,默认为1

file= verbose= quiet= long=
while [[ $# -gt 0 ]]; do                 # 依次处理命令行参数,没处理依次,$#都减1
case $1 in
-f )
file=$2
echo "file = $file"
shift                        # 因为-f选项后面要跟文件名,所以还得再shift一遍
;;
-v )
verbose=true
quiet=false
echo "verbose = $verbose"
echo "quiet = $quiet"
;;
-q )
quiet=true
verbose=false
echo "verbose = $verbose"
echo "quiet = $quiet"
;;
-l )
long=true
echo "long = $long"
;;
esac
shift
done


getopts

简化命令行参数处理

第一个参数是所有合法参数的字符串;如果选项字母后面跟冒号,说明该选项后面需要一个参数,且是必填的;如果遇到需要参数的选项,将参数值放置到变量OPTARG中

OPTIND包含下一个要处理的参数的索引值,初始值为1

第二个参数为变量名称,每次getopts时,该变量会被更新,值等于找到的选项字母;遇到不合法的选项时,该变量被置为?

file= verbose= quiet= long= a=

while getopts f:vqa:l opt
do
case $opt in
f )
file=$OPTARG
echo "file = $file"
;;
a )
a=$OPTARG
echo "a = $a"
;;
v )
verbose=true
quiet=false
echo "verbose = $verbose"
echo "quiet = $quiet"
;;
q )
verbose=false
quiet=true
echo "verbose = $verbose"
echo "quiet = $quiet"
;;
l )
long=true
echo "long = $long"
;;
esac
done


函数

函数使用前必须先定义

在脚本的起始处定义

在一个独立文件里定义,在脚本中用”.”符号获取

wait_for_user(){
XXX
}


return

从函数里返回值

如果为指定参数,使用默认退出状态

return $?  # 严谨的写法


函数参数

在函数中,位置参数代表函数参数;当函数完成时,原来的命令行参数会恢复

涉及到的命令

export

readonly

env

unset

exit

return

test

shift

getopts
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: