1. 变量命名

变量命名只能使用数字、下划线、字母,且仅能以下划线或字母开头。

变量很少使用单个字母,单个字母一般用于循环或读取一次性文件的时候。

例:

while IFS=: read login a b c name e
do
printf "%-12s %s\n" "$login" "$name"
done < /etc/passwd 

变量名最好能望名知意

2. 变量作用域

若脚本a调用脚本b,则a无法得知b中的变量,除非将b中的变量写入环境变量中。

脚本中在变量前使用export内置命令,则可以将该变量设置为环境变量。

如:

var=whatever
export var # bash中可简写为export var=whatever 

导出(export)一个变量并不是在任何地方都可以访问该变量,除了子进程外。

例:showvar用于检验变量是否被设置

if [[ ${x+Z} = Z ]] ## $x被设置
then
echo ${x+Z}
echo Z
if [[ -n $x ]] ## $x非空
then
printf " \$x = %s\n" "$x"
else
printf " \$x is set but empty\n"
fi
else
printf " %s is not set\n" "\$x"
fi 

若导出了一个变量,其一直保留在环境中,除非直接unset命令。

$ unset x
$ mv variable showvar
$ ./showvar
$x is not set
$ x=
$ ./showvar
$x is not set
$ export x=
$ ./showvar
$x =
$ x= ## bash中,对一个变量重新赋值,并不会从环境变量中移除该变量
$ ./showvar
$x is set but empty 

设置在子shell中的变量对调用它的脚本不可见。子shell包含命令替换,如$(command) 或`command`; 管道中的所有元素;括号中的内容,如( command )

例:

printf "%s\n" ${RANDOM}{,,,,,} |
while read num
do
(( num > ${biggest:=} )) && biggest=$num
done
printf "The largest number is: %d\n" "$biggest" 

执行该脚本,发现biggest为0,原因在于循环是管道的一部分,将会在子shell中执行它,而子shell中的变量对该执行脚本不可见。

bash4.2中,新的选项lastpipe,允许管道中最后的进程在当前shell中执行,通过调用:shopt -s lastpipe

3. Shell变量

shell自带变量BASH_VERSION表示bash的版本。

例:

case $BASE_VERSION in [].*) echo "You need at least bash3.0 to run this script" >&; exit ;;
esac 

提示符PS1,PS2用于命令行中的shell交互时,PS3在使用内置命令select时使用,PS4用于在执行跟踪模式下,每行之前的打印。

Shell变量包含:

BASH BASHOPTS BASHPID BASH_ALIASES
BASH_ARGC BASH_ARGV BASH_CMDS BASH_COMMAND
BASH_EXECUTION_STRING BASH_LINENO BASH_REMATCH BASH_SOURCE
BASH_SUBSHELL BASH_VERSINFO BASH_VERSION COMP_CWORD
COMP_KEY COMP_LINE COMP_POINT COMP_TYPE
COMP_WORDBREAKS COMP_WORDS COPROC DIRSTACK
EUID FUNCNAME GROUPS HISTCMD
HOSTNAME HOSTTYPE LINENO MACHTYPE
MAPFILE OLDPWD OPTARG OPTIND
OSTYPE PIPESTATUS PPID PWD
RANDOM READLINE_LINE READLINE_POINT REPLY
SECONDS SHELLOPTS SHLVL UID
BASH_COMPAT BASH_ENV BASH_XTRACEFD CDPATH
CHILD_MAX COLUMNS COMPREPLY EMACS
FCEDIT FIGNORE FUNCNEST GLOBIGNORE
HISTCONTROL HISTFILE HISTFILESIZE HISTIGNORE
HISTSIZE HISTTIMEFORMAT HOME HOSTFILE
IFS IGNOREEOF INPUTRC LANG
LC_ALL LC_COLLATE LC_CTYPE LC_MESSAGES
LC_NUMERIC LC_NUMERIC LINES MAIL
MAILCHECK MAILPATH OPTERR PATH
POSIXLY_CORRECT PROMPT_COMMAND PROMPT_DIRTRIM PS1
PS2 PS3 PS4 SHELL
TIMEFORMAT TMOUT TMPDIR auto_resume
histchars 

4. 参数扩展

(1) ${var:-default}和${var-default}:使用默认值

## ${var:-default}用于检查变量未被设置或为空,若为空或未被设置,则使用默认值
$ var=
$ ./sa ${var:-default}
:default: ## 如果取掉":",则${var-default}仅检测变量是否为unset
$ ./sa ${var-default}
::
$ unset var
$ ./sa ${var-default}
:default: # 为filename设置默认值
defaultfile=$HOME/.bashrc
## parse options here
filename=${filename:-"$defaultfile"} 

(2) ${var:+altername}, ${var+alternate}: 使用替换值

## $var设置但为空,因此替换值不生效
$ var=
$ ./sa "${var:+alternate}"
:: ## $var被设置,且不为空,则替换值生效
$ ./sa ${var:+alternate}
:alternate: ## 取消冒号后,即使变量为空,只要被设置,替换值将生效
$ var=
$ ./sa "${var+alternate}" ## $var被设置
:alternate:
$ unset var
$ ./sa "${var+alternate}" ## $var未被设置
::
$ var=value
$ ./sa "${var+alternate}" ## $var被设置且非空
:alternate: 

常用于变量中增加字符串。例:

## 变量为空时,不想在变量中增加分隔符
$ var=
$ for n in a b c d e f g
> do
> var="$var $n"
> done
$ ./sa "$var"
: a b c d e f g: # 为了防止a前面的空格,可以使用参数扩展
$ var=
$ for n in a b c d e f g
> do
> var="${var:+"$var "}$n" # $var被设置且非空时,则替换为"$var "
> done
$ ./sa "$var"
:a b c d e f g: # 上面的方法是如下2个方法方法的简写
#
if [ -n "$var" ]
then
var="$var $n"
else
var=$n
fi
#
[ -n "$var" ] && var="$var $n" || var=$n 

(3) ${var:=default}, ${var=default}: 赋初始值

${var:=default}与${var:-default}类似,不同之处在于它也向变量赋初始值。

$ unset n
$ while :
> do
> echo :$n:
> [ ${n:=} -gt ] && break ## 如果未被设置或为空,则将$n设为0
> n=$(( $n + ))
> done
::
::
::
::
:: 

(4) ${var:?message}, ${var?message}: 如果为空或未被设置,则显示错误信息到标准错误输出

$ ./checkarg
./checkarg: line : : An argument is required
$ ./checkarg x
./checkarg: line : : Two arguments are required
$ ./checkarg '' ''
./checkarg: line : : A non-empty argument is required
$ ./checkarg x ''
./checkarg: line : : Two non-empty arguments are required
$ ./checkarg x x
Thank you. 

(5) ${#var}: 变量内容的长度

read passwd
if [ ${#passwd} -lt ]
then
printf "Password is too short: %d characters\n" "$#" >&
exit
fi 

(6)  ${var%PATTERN}: 从变量结尾移除最短匹配

$ var=Toronto
$ var=${var%o*}
$ printf "%s\n" "$var"
Toront
$ printf "%s\n" "${var%o*}"
Tor # dname, 打印文件路径的部分
case $ in
*/*) printf "%s\n" "${1%/*}" ;;
*) [ -e "$1" ] && printf "%s\n" "$PWD" || echo "." ;;
esac $ ./dname /etc/passwd
/etc
$ ./dname bin

(7) ${var%%PATTERN}: 从变量结尾移除最长匹配

$ var=Toronto
music@ds01:~/songwang4/test$ ./sa "${var%%o*}"
:T: 

(8) ${var#PATTERN}: 从变量起始处移除最短匹配

$ var=Toronto
$ ./sa "${var#*o}"
:ronto: 

(9) ${var##PATTERN}: 从变量起始处移除最长匹配

scriptname=${##*/} ## /home/chris/bin/script => script 

(10) ${var//PATTERN/STRING}: 使用STRING替换所有的PATTERN实例

## 密码隐藏显示
$ passwd=zx01.=+-a
$ printf "%s\n" "${passwd//?/*}"
********* ## 单斜杠"/"仅替换第一个匹配的字符
$ printf "%s\n" "${passwd/a/*}"
zx01.=+-* 

(11) ${var:OFFSET:LENGTH}: 返回$var的子串

OFFSET表示起始位置,LENGTH表示截取长度。

$ var=Toronto
$ ./sa "${var:3:2}"
:on:
$ ./sa "${var:3}"
:onto: ## 负数表示从字符串结尾开始
$ ./sa "${var: -3}" ## 注意-3前面的空格,防止与变量默认值扩展混淆
:nto: 

(12) ${!var}: 间接引用

若变量中含有另一个变量的名称,bash可以使用间接引用。

$ x=yes
$ a=x
$ ./sa ${!a}
:yes: ## 使用eval也可实现类似功能
$ eval "./sa \$$a"
:yes: 

(13) ${var^PATTERN}: 大写转换

如果匹配PATTERN,则var的第一个字符转换为大写;当为^^时,匹配到PATTERN的所有字符转换为大写;如果PATTERN为空,则所有都匹配。

$ var=toronto
$ ./sa "${var^}" ## PATTERN为空且为^,时,第一个字符大写转换
:Toronto:
$ ./sa "${var^[n-z]}"
:Toronto: $ ./sa "${var^^[a-o]}" ## 匹配从a到o的所有字符
:tOrONtO
$ ./sa "${var^^}" ## 匹配所有
:TORONTO: 

(14) ${var,PATTERN}:小写转换

与${var^PATTERN}用法相同,区别在于小写转换

$ var=TORONTO
$ ./sa "${var,,}"
:toronto:
$ ./sa "${var,,[N-Q]}"
:ToRonTo: 

(15) ${var~}:大小写取反

$ var=Toronto
$ ./sa "${var~}"
:toronto:
$ ./sa "${var~~}"
:tORONTO: 

5. 位置参数

位置参数由$1,...${10}引用,全部参数可以使用"$@"或"$*",大于9的索引参数需要以大括号封装。

不带参数的shift命令将会移除第一个参数,并将剩余的参数前移一位,如历史的$2将会变为$1。带参数的shift将会移动指定的大小。

$ shift  ## 移除前3个参数
$ shift "$#" ## 移除所有参数
$ shift "$(( $# -2 ))" ## 保留最后2位参数 ## 使用每一个参数,可以通过如下2种方法
## . 使用$@
for param in "#@" ## 或 for param
do
: do something with $param
done ## . 使用shift
while (( $# ))
do
: do something with $
shift
done 

6. 数组

(1) 整型索引数组

数组元素索引从0开始。Bash中的数组是稀疏的,即索引号可以不连续。

# BASH_VERSINFO表示当前运行shell的版本信息,第一个元素表示主版本号,第二个表示次版本号
$ printf "%s\n" "${BASH_VERSINFO[0]}" $ printf "%s\n" "${BASH_VERSINFO[1]}"

可以使用*和@打印数组所有元素。当使用"*"且数组被引号括起,则数组元素不会拆分,若没有引号则会被拆分;当使用"@"时,均会被拆分

$ printf "%s\n" "${BASH_VERSINFO[*]}" # 不拆分
release x86_64-pc-linux-gnu
$ printf "%s\n" ${BASH_VERSINFO[*]} # 拆分 release
x86_64-pc-linux-gnu
$ printf "%s\n" ${BASH_VERSINFO[@]} # 使用@时,默认均拆分,对仅限于数组元素间的拆分,而不会涉及到元素内容 release
x86_64-pc-linux-gnu ## 提取数组中第二个和第三个元素
$ printf "%s\n" "${BASH_VERSINFO[@]:1:2}" ## 当使用*或@时,"#"返回数组长度,如果指定数组元素时,则返回数组元素的长度
$ printf "%s\n" "${#BASH_VERSINFO[*]}" $ printf "%s\n" "${#BASH_VERSINFO[2]}" "${#BASH_VERSINFO[5]}" ## 数组通过下标赋值
$ name[]=
$ name[]= ## 非连续下标的好处,原因在于对它们的操作将变得简单,直接取下一个未被设置的元素即可
$ unset a
$ a[${#a[@]}]="1 $RANDOM"
$ a[${#a[@]}]="2 $RANDOM"
$ a[${#a[@]}]="3 $RANDOM"
$ a[${#a[@]}]="4 $RANDOM"
$ printf "%s\n" "${a[@]}" ## 数组也可以仅使用如下一个命令生成
$ province=( Quebec Ontario Manitoba )
$ printf "%s\n" "${province[@]}"
Quebec
Ontario
Manitoba ## +=用于在数组索引末位添加值
$ province+=( Saskatchewan )
$ province+=( Alberta "British Columbia" "Nova Scotia" )
$ printf "%-25s %-25s %s\n" ${province[@]}
Quebec Ontario Manitoba
Saskatchewan Alberta British
Columbia Nova Scotia
$ printf "%-25s %-25s %s\n" "${province[@]}"
Quebec Ontario Manitoba
Saskatchewan Alberta British Columbia
Nova Scotia 

(2) 关联数组

bash 4后,允许使用字符串作为下标,且数组必须先声明。

$ declare -A array
$ for subscript in a b c d e
> do
> array[$subscript]="$subscrupt $RANDOM"
> done
$ printf ":%s:\n" "${array["c"]}" ## 打印单个元素
: :
$ printf ":%s:\n" "${array[@]}" ## 打印整个数组
: :
: :
: :
: :
: : 

Bash编程(4) 参数与变量的更多相关文章

  1. bash编程总结

    bash应该是目前Linux上最流行的shell脚本解释程序了(还有个shell叫dash,我太讨厌这个东东了.),只要你在linux上工作,并且希望自己能够工作得更愉悦,那么你应该熟悉最基本的bas ...

  2. bash编程2

    bash基础编程 前言:条件测试语法有两种书写模式,一种时[expression] ,另外一种是[[exprssion]] ,为了在书写条件测试的过程中,不让大家将两种格式互相混淆,那么在这里只讲一种 ...

  3. bash编程基础

    bash变量 变量命名: 1.不能使用程序中的关键字(保留字) 2.只能使用数字.字母和下划线,且不能以数字开头 3.要见名知义 变量类型: 数值型:精确数值(整数),近似数值(浮点型) 字符型:ch ...

  4. bash的位置变量和特殊变量

    bash编程的知识点:位置变量和特殊变量 位置参数变量:         scirpt1.sh arg1 arg2 ...         $0         $1   $2   ...  ${10 ...

  5. [shell] Bash编程总结

    由于工作需要,之前的几个月写了一些Bash脚本,主要完成自动测试.打包.安装包等.虽然相比C++编程,要简单.傻瓜,但其在类Unix系统中可以大大提高工作的效率.所以在此对脚本编程过程中一些注意事项进 ...

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

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

  7. Linux Bash编程

    在Linux系统介绍中,介绍了shell的多个版本,现在的Linux发行版基本都默认使用bash(Bourne Again shell),兼容Bourne shell (sh),本文将简要介绍Bash ...

  8. bash编程之多分支if 语句及for循环

    第十七章.bash编程之多分支if 语句及for循环 if语句三种格式 多分支if语句练习 for循环 17.1.if语句的三种格式 单分支if语句 if condition;then 条件为真执行的 ...

  9. Linux多线程编程详细解析----条件变量 pthread_cond_t

    Linux操作系统下的多线程编程详细解析----条件变量 1.初始化条件变量pthread_cond_init #include <pthread.h> int pthread_cond_ ...

随机推荐

  1. Backup--完整备份会打破现有的日志备份链么?

    --问题描述: --对数据库有一个周期性数据库备份和事务日志备份的维护计划,在维护计划外有工作人员对数据库进行完整备份,该备份会打乱现有的日志备份链么? --===================== ...

  2. 一个简单的C#+arcgis的非数据库版例子

    1.首先新建一个winform的项目. 2.确保C#工具箱包含ESRI的相关控件,如果没有就需要安装SDK. 如果VS中依旧不存在esri控件解决方案如下,以VS2013为例: (1)打开注册表,定位 ...

  3. OLEDB导入导出Excel

    using System;using System.Collections.Generic;using System.Data;using System.Data.OleDb;using System ...

  4. 爬虫开发10.scrapy框架之日志等级和请求传参

    今日概要 日志等级 请求传参 今日详情 一.Scrapy的日志等级 - 在使用scrapy crawl spiderFileName运行程序时,在终端里打印输出的就是scrapy的日志信息. - 日志 ...

  5. python设计模式-适配器

    定义: 将一个接口转换为客户希望的另一个接口,该模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作 适配器模式又叫变压器模式,也叫包装模式(Wrapper),它的核心思想是将一个对象经过包装 ...

  6. Flink学习笔记:Flink API 通用基本概念

    本文为<Flink大数据项目实战>学习笔记,想通过视频系统学习Flink这个最火爆的大数据计算框架的同学,推荐学习课程: Flink大数据项目实战:http://t.cn/EJtKhaz ...

  7. 函数新特性、内联函数、const详解

    一.函数回顾与后置返回类型 函数定义中,形参如果在函数体内用不到的话,则可以不给形参变量名字,只给其类型. 函数声明时,可以只有形参类型,没有形参名 把函数返回类型放到函数名字之前,这种写法,叫前置返 ...

  8. 手把手教你在CentOS 7.4下搭建Zabbix监控(转)

    Linux系统版本:CentOS 7.4 1.安装前需要先关闭selinux和firewall. 1.1 [root@zabbix ~]# vi /etc/selinux/config 将SELINU ...

  9. Advanced-REST-client安装

    下载得到Advanced-REST-client_v3.1.9.zip:链接:http://pan.baidu.com/s/1c0vUnJi 密码:z34d这里要说明下,目前谷歌浏览器是不允许安装非谷 ...

  10. editplus 编辑 php双击选中变量问题

    windows下,在很多地方双击鼠标左键可以选中一个连续的英文字符串. 在editplus 编辑器里可以双击选中一个变量,方便了编程,但是使用phptools(php.stx)增强语法插件后,在一个变 ...