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
特殊变量
变量 | 意义 |
---|---|
0 | Shell程序名称 |
# | 参数个数 |
@ | 命令行参数,如果在”“内,则展开为一系列单独的参数 |
* | 命令行参数,如果在”“内,则把所有参数合并为一个字符串 |
$ | 当前进程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 file | file存在 |
-s file | file不为空 |
-f file | file是一般文件 |
-d file | file是目录 |
-b file | file是块设备文件 |
-c file | file是字符设备文件 |
-p file | file是命名管道(FIFO) |
-S file | file是socket |
-h file | file是符号链接 |
-L file | file是符号链接,同-h |
-r file | file是可读的 |
-w file | file是可写入的 |
-x file | file是可执行的,或file是可被查找的目录 |
-g file | file有设置setgid位 |
-u file | file有设置setuid位 |
string | string不是null |
-n string | string非null |
-z string | string是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 $? # 严谨的写法
函数参数
在函数中,位置参数代表函数参数;当函数完成时,原来的命令行参数会恢复
涉及到的命令
exportreadonly
env
unset
exit
return
test
shift
getopts
相关文章推荐
- hbase基本概念和hbase shell常用命令用法
- linux shell 特殊变量
- shell脚本+x
- ~/.bashrc 和 ~/.bash_profile 和 /etc/bashrc 和 /etc/profile 脚本的区别和启动加载顺序
- Windows日志管理相关脚本
- Delete log files longer than 45 days
- shell-5.shell echo 命令
- Deploy NRPE config files
- Powershell check server patch status
- 在shell中如何把10进制字符转换成16进制形式输出?
- shell-4.shell双引号,单引号,反引号,反斜杠
- 用shell监控站点目录下的文件是否被修改
- shell-3.shell特殊变量
- shell脚本中修改文件的内容
- shell编程笔记
- Jenkins+SVN+Maven+Shell 实现项目一键发布
- shell-2.shell定义变量
- vim和xshell配色
- adb shell 查看手机根目录
- /etc/profile、~/.bash_profile等几个文件的执行过程