Bash 学习摘录
文章目录
- 1、变量和参数的介绍
- (1)变量替换
- $(...)
- (2)特殊的变量类型
- export
- 位置参数
- shift
- 2、引用
- (1)引用变量
- (2)转义
- 3、条件判断
- (1)条件测试结构
- (2)文件测试操作符
- (3)其他比较操作符
- 整数比较
- 字符串比较
- compound comparison
- 4、数字常量
- 5、变量重游
- (1) 内部变量
- 内建变量
- 位置参数
- 其他的特殊参数
- (2) 操作字符串
- 字符串长度
- 匹配字符串开头的子串长度
- 索引
- 提取子串
- 子串削除
- 子串替换
- (3) 参数替换
- 处理和(或)扩展变量
- (4)指定变量的类型: 使用 declare 或者 typeset
- (5)变量的间接引用
- (6)$RANDOM: 产生随机整数
- (7)双圆括号结构
1、变量和参数的介绍
(1)变量替换
$(…)
使用 $(…) 机制来进行变量赋值(这是一种比后置引用(反引号`)更新的一种方法)。 事实上这两种方法都是命令替换的一种形式。
arch=$(uname -m)
(2)特殊的变量类型
export
一个脚本只能够 export 变量到这个脚本所产生的子进程, 也就是说只能够对这个脚本所产生的命令和进程起作用。 如果脚本是从命令行中调用的, 那么这个脚本所 export 的变量是不能影响命令行环境的。 也就是说, 子进程是不能够 export 变量来影响产生自己的父进程的环境的。
位置参数
从命令行传递到脚本的参数: $0, $1, $2, $3 . . .
$0 就是脚本文件自身的名字, $1 是第一个参数, $2 是第二个参数, $3 是第三个参数, 然后是第四个。 $9 之后的位置参数就必须用大括号括起来了, 比如, ${10}, ${11}, ${12} 。
两个比较特殊的变量 $* 和 $@ 表示所有的位置参数。
shift
shift 命令会重新分配位置参数, 其实就是把所有的位置参数都向左移动一个位置。
$1 <— $2, $2 <— $3, $3 <— $4, 等等。
原来的 $1 就消失了, 但是 $0 (脚本名) 是不会改变的。 如果传递了大量的位置参数到脚本中, 那么 shift 命令允许你访问的位置参数的数量超过 10 个, 当然 {} 标记法也提供了这样的功能。
2、引用
(1)引用变量
双引号中通过直接使用变量名的方法来引用变量。单引号 (’ ') 操作与双引号基本一样, 但是不允许引用变量, 因为 $ 的特殊意义被关闭了。
(2)转义
- \0xx
转换为八进制的 ASCII 码, 等价于 0xx
3、条件判断
(1)条件测试结构
-
test, /usr/bin/test, [ ], 和 /usr/bin/[ 都是等价命令
-
[[ ]] 结构比 [ ] 结构更加通用。 这是一个扩展的 test 命令, 是从 ksh88 中引进的。
-
(( )) 结构扩展并计算一个算术表达式的值
(2)文件测试操作符
- -e
文件存在 - -a
文件存在。这个选项的效果与 -e 相同。 但是它已经被 “弃用” 了, 并且不鼓励使用。 - -f
表示这个文件是一个一般文件 (并不是目录或者设备文件) - -s
文件大小不为零 - -d
表示这是一个目录 - -b
表示这是一个块设备 (软盘, 光驱, 等等。) - -c
表示这是一个字符设备 (键盘, modem, 声卡, 等等。) - -p
这个文件是一个管道 - -h
这是一个符号链接 - -L
这是一个符号链接 - -S
表示这是一个 socket - -t
文件(描述符)被关联到一个终端设备上。这个测试选项一般被用来检测脚本中的 stdin([ -t 0 ]) 或者 stdout([ -t 1 ]) 是否来自于一个终端。 - -r
文件是否具有可读权限(指的是正在运行这个测试命令的用户是否具有读权限) - -w
文件是否具有可写权限(指的是正在运行这个测试命令的用户是否具有写权限) - -x
文件是否具有可执行权限(指的是正在运行这个测试命令的用户是否具有可执行权限) - -g
set-group-id(sgid) 标记被设置到文件或目录上。
如果目录具有 sgid 标记的话, 那么在这个目录下所创建的文件将属于拥有这个目录的用户组, 而不必是创建这个文件的用户组。 这个特性对于在一个工作组中共享目录非常有用。 - -u
set-user-id (suid) 标记被设置到文件上。
如果一个 root 用户所拥有的二进制可执行文件设置了 set-user-id 标记位的话, 那么普通用户也会以 root 权限来运行这个文件。 - -k
设置粘贴位
对于 “粘贴位” 的一般了解, save-text-mode 标志是一个文件权限的特殊类型。 如果文件设置了这个标志, 那么这个文件将会被保存到缓存中, 这样可以提高访问速度。 - -O
判断你是否是文件的拥有者 - -G
文件的 group-id 是否与你的相同 - -N
从文件上一次被读取到现在为止, 文件是否被修改过 - f1 -nt f2
文件 f1 比文件 f2 新 - f1 -ot f2
文件 f1 比文件 f2 旧 - f1 -ef f2
文件 f1 和文件 f2 是相同文件的硬链接 - !
“非” —— 反转上边所有测试的结果(如果没给出条件, 那么返回真)。
(3)其他比较操作符
二元比较操作符用来比较两个变量或数字。 注意整数比较与字符串比较的区别。
整数比较
-
-eq
等于
if [ “$a” -eq “$b” ] -
-ne
不等于
if [ “$a” -ne “$b” ] -
-gt
大于
if [ “$a” -gt “$b” ] -
-ge
大于等于
if [ “$a” -ge “$b” ] -
-lt
小于
if [ “$a” -lt “$b” ] -
-le
小于等于
if [ “$a” -le “$b” ] -
<
小于(在双括号中使用)
((“$a” < “$b”)) -
<=
小于等于(在双括号中使用)
((“ a " < = " a" <= " a"<="b”)) -
>
大于(在双括号中使用)
((“$a” > “$b”)) -
>=
大于等于(在双括号中使用)
((“$a” >= “$b”))
字符串比较
-
=
等于
if [ “$a” = “$b” ] -
==
等于
if [ “$a” == “$b” ]
与 = 等价。 -
!=
不等号
if [ “$a” != “$b” ]
这个操作符将在 [[ … ]] 结构中使用模式匹配。 -
<
小于, 按照 ASCII 字符进行排序
if [[ “$a” < “$b” ]]
if [ “$a” \< “$b” ]
注意 “<” 使用在 [ ] 结构中的时候需要被转义。 -
>
大于, 按照 ASCII 字符进行排序
if [[ “$a” > “$b” ]]
if [ “$a” \> “$b” ]
注意 “>” 使用在 [ ] 结构中的时候需要被转义。 -
-z
字符串为 “null” , 意思就是字符串长度为零 -
-n
字符串不为 “null” 。
compound comparison
-
-a
逻辑与
exp1 -a exp2 如果表达式 exp1 和 exp2 都为真的话, 那么结果为真。 -
-o
逻辑或
exp1 -o exp2 如果表达式 exp1 和 exp2 中至少有一个为真的话, 那么结果为真。
4、数字常量
shell 脚本在默认情况下都是把数字作为 10 进制数来处理, 除非这个数字采用了特殊的标记或者前缀。
如果数字以 0 开头的话那么就是 8 进制数。 如果数字以 0x 开头的话那么就是 16 进制数。 如果数字中间嵌入了 # 的话, 那么就被认为是 BASE#NUMBER 形式的标记法(有范围和符号限制)。
# 其他进制: BASE#NUMBER
# BASE 的范围在 2 到 64 之间.
# NUMBER 的值必须使用 BASE 范围内的符号来表示, 具体看下边的示例.let "bin = 2#111100111001101"
echo "binary number = $bin" # 31181let "b32 = 32#77"
echo "base-32 number = $b32" # 231
5、变量重游
(1) 内部变量
内建变量
这些变量将会影响 bash 脚本的行为。
- $BASH
Bash 的二进制程序文件的路径
$ echo $BASH
/bin/bash
-
$BASH_ENV
这个环境变量会指向一个 Bash 的启动文件, 当一个脚本被调用的时候, 这个启动文件将会被读取。 -
$BASH_SUBSHELL
这个变量用来提示子 shell 的层次。 这是一个 Bash 的新特性, 直到版本 3 的 Bash 才被引入近来。 -
$BASH_VERSINFO[n]
这是一个含有 6 个元素的数组, 它包含了所安装的 Bash 的版本信息。 这与下边的 $BASH_VERSION 很相像, 但是这个更加详细一些。
# Bash version info:
for n in 0 1 2 3 4 5; doecho "BASH_VERSINFO[$n] = ${BASH_VERSINFO[$n]}"
done
# BASH_VERSINFO[0] = 3 # 主版本号
# BASH_VERSINFO[1] = 00 # 次版本号。
# BASH_VERSINFO[2] = 14 # 补丁次数。
# BASH_VERSINFO[3] = 1 # 编译版本。
# BASH_VERSINFO[4] = release # 发行状态。
# BASH_VERSINFO[5] = i386-redhat-linux-gnu # 结构体系# (与变量$MACHTYPE相同)。
- $BASH_VERSION
安装在系统上的 Bash 版本号
bash$ echo $BASH_VERSION
3.00.14(1)-releasetcsh% echo $BASH_VERSION
BASH_VERSION: Undefined variable.
-
$DIRSTACK
在目录栈中最顶端的值。 (将会受到 pushd 和 popd 的影响)
这个内建变量与 dirs 命令相符, 但是 dirs 命令会显示目录栈的整个内容。 -
$EDITOR
脚本所调用的默认编辑器, 通常情况下是 vi 或者是 emacs 。 -
$EUID
“有效” 用户 ID 。
不管当前用户被假定成什么用户, 这个数都用来表示当前用户的标识号, 也可能使用 su 命令来达到假定的目的。
$EUID 并不一定与 $UID 相同。 -
$FUNCNAME
当前函数的名字。(数组形式 $FUNCNAME[0] ) -
$GLOBIGNORE
一个文件名的模式匹配列表,如果在通配(globbing)中匹配到的文件包含有这个列表中的某个文件, 那么这个文件将被从匹配到的结果中去掉。 -
$GROUPS
目前用户所属的组。
这是一个当前用户的组 id 列表(数组), 与记录在 /etc/passwd 文件中的内容一样。
root# echo $GROUPS
0
root# echo ${GROUPS[1]}
1
root# echo ${GROUPS[5]}
6
-
$HOME
用户的 home 目录, 一般是 /home/username -
$HOSTNAME
hostname 放在一个初始化脚本中, 在系统启动的时候分配一个系统名字。 然而, gethostname() 函数可以用来设置这个 Bash 内部变量 $HOSTNAME 。 -
$HOSTTYPE
主机类型
就像 $MACHTYPE , 用来识别系统硬件。
bash$ echo $HOSTTYPE
i686
-
$IFS
内部域分隔符
这个变量用来决定 Bash 在解释字符串时如何识别域, 或者单词边界。
$IFS 默认为 空白(空格, 制表符,和换行符), 但这是可以修改的, 比如, 在分析逗号分隔的数据文件时, 就可以设置为逗号。 注意 $* 使用的是保存在 $IFS 中的第一个字符。 -
$IGNOREEOF
忽略 EOF : 告诉 shell 在 log out 之前要忽略多少文件结束符(control-D)。 -
$LC_COLLATE
常在 .bashrc 或 /etc/profile 中设置, 这个变量用来控制文件名扩展和模式匹配的展开顺序。 如果 $LC_COLLATE 设置得不正确的话, LC_COLLATE 会在文件名匹配(filename globbing)中产生不可预料的结果。 -
$LC_CTYPE
这个内部变量用来控制通配(globbing)和模式匹配中的字符串解释。 -
$LINENO
这个变量用来记录自身在脚本中所在的行号。 这个变量只有在脚本使用这个变量的时候才有意义,并且这个变量一般用于调试目的。 -
$MACHTYPE
机器类型。标识系统的硬件。
bash$ echo $MACHTYPE
i686
-
$OLDPWD
之前的工作目录(“OLD-print-working-directory”, 就是之前你所在的目录) -
$OSTYPE
操作系统类型 -
$PATH
可执行文件的搜索路径, 一般为 /usr/bin/, /usr/X11R6/bin/, /usr/local/bin, 等等。 -
$PIPESTATUS
这个数组变量将保存最后一个运行的前台管道的退出状态码。 相当有趣的是, 这个退出状态码和最后一个命令运行的退出状态码并不一定相同。 -
$PPID
进程的 $PPID 就是这个进程的父进程的进程 ID(pid)。 -
$PROMPT_COMMAND
这个变量保存了在主提示符 $PS1 显示之前需要执行的命令。 -
$PS1
这是主提示符, 可以在命令行中见到它。 -
$PS2
第二提示符, 当你需要额外输入的时候, 你就会看到它。 默认显示 “>” 。 -
$PS3
第三提示符, 它在一个 select 循环中显示 。 -
$PS4
第四提示符, 当你使用 -x 选项来调用脚本时, 这个提示符会出现在每行输出的开头。 默认显示 “+” 。 -
$PWD
工作目录(你当前所在的目录) -
$REPLY
当没有参数变量提供给 read 命令的时候, 这个变量会作为默认变量提供给 read 命令。 也可以用于 select 菜单, 但是只提供所选择变量的编号, 而不是变量本身的值。 -
$SECONDS
这个脚本已经运行的时间(以秒为单位)。 -
$SHELLOPTS
shell 中已经激活的选项的列表, 这是一个只读变量。
bash$ echo $SHELLOPTS
braceexpand:hashall:histexpand:monitor:history:interactivecomments:emacs
-
$SHLVL
Shell 级别, 就是 Bash 被嵌套的深度。 如果是在命令行中, 那么 $SHLVL 为 1, 如果在脚本中那么 $SHLVL 为 2 。 -
$TMOUT
如果 $TMOUT 环境变量被设置为非零值 time 的话, 那么经过 time 秒后, shell 提示符将会超时。 这将会导致登出(logout)。 -
$UID
用户 ID 号。当前用户的用户标识号, 记录在 /etc/passwd 文件中
位置参数
-
$0, $1, $2, 等等。
位置参数, 从命令行传递到脚本, 或者传递给函数, 或者 set 给变量 -
$#
命令行参数或者位置参数的个数 -
$*
所有的位置参数都被看作为一个单词。
“$*” 必须被引用起来。 -
$@
与 $* 相同, 但是每个参数都是一个独立的引用字符串, 这就意味着, 参数是被完整传递的, 并没有被解释或扩展。 这也意味着, 参数列表中每个参数都被看作为单独的单词。
“$@” 应该被引用起来。
其他的特殊参数
-
$-
传递给脚本的标记(使用 set 命令)。 -
$!
运行在后台的最后一个作业的 PID(进程 ID) -
$_
这个变量保存之前执行的命令的最后一个参数的值 -
$?
命令, 函数, 或者是脚本本身的退出状态码 -
$$
脚本自身的进程 ID。 $$ 变量在脚本中经常用来构造 “唯一的” 临时文件名
(2) 操作字符串
Bash 所支持的字符串操作的数量多的令人惊讶。 但是不幸的是, 这些工具缺乏统一的标准。 一些是参数替换的子集, 而另外一些则受到 UNIX expr 命令的影响。 这就导致了命令语法的不一致, 还会引起冗余的功能, 但是这些并没有引起混乱。
expr --help
用法:expr 表达式或:expr 选项--help 显示此帮助信息并退出--version 显示版本信息并退出将 <表达式> 的值打印到标准输出。以下运算符按优先级从低到高排列,不同
优先级之间以空行隔开。<表达式> 可以是:参数1 | 参数2 若 <参数1> 的值不为 0 或 null,则返回 <参数1>,否则返回 <参数2>参数1 & 参数2 若两边的值都不为 0 或 null,则返回 <参数1>,否则返回 0参数1 < 参数2 <参数1> 小于 <参数2>参数1 <= 参数2 <参数1> 小于或等于 <参数2>参数1 = 参数2 <参数1> 等于 <参数2>参数1 != 参数2 <参数1> 不等于 <参数2>参数1 >= 参数2 <参数1> 大于或等于 <参数2>参数1 > 参数2 <参数1> 大于 <参数2>参数1 + 参数2 计算 <参数1> 加 <参数2> 的和参数1 - 参数2 计算 <参数1> 减 <参数2> 的差参数1 * 参数2 计算 <参数1> 乘以 <参数2> 的积参数1 / 参数2 计算 <参数1> 除以 <参数2> 的商参数1 % 参数2 计算 <参数1> 除以 <参数2> 的余数字符串 : 正则 在 <字符串> 起始处进行 <正则> 的模式匹配match 字符串 正则 等于 "字符串 : 正则"substr 字符串 位置 长度 求 <字符串> 的子串,<位置> 从 1 开始数index 字符串 字符 在 <字符串> 中搜索 <字符> 中任何一个,返回其索引,如未找到则返回 0length 字符串 <字符串> 的长度+ 记号 将 <记号> 解释为字符串,即使它是一个关键字,例如 "match",或者运算符,例如 "/"( 表达式 ) <表达式> 的值请注意,由于 shell 这一层的存在,可能有许多运算符需要转义或者加引号。
如果两个 <参数> 都是数字,比较运算符就是算术比较,否则就是字典序比较。
模式匹配会返回 \( 和 \) 之间的字符串匹配的字符串,若没有匹配则返回 null;
如果未使用 \( 和 \),则会返回匹配的字符的个数,若没有匹配则返回 0。若 <表达式> 的值既不是 null 也不是 0,则退出状态为 0;若 <表达式> 的值为 null
或者 0,则退出状态为 1;如果 <表达式> 的句法无效,则退出状态为 2;如果有错误
发生,则退出状态为 3。GNU coreutils 在线帮助:<https://www.gnu.org/software/coreutils/>
请向 <http://translationproject.org/team/zh_CN.html> 报告任何翻译错误
完整文档 <https://www.gnu.org/software/coreutils/expr>
或者在本地使用:info '(coreutils) expr invocation'
字符串长度
语法:
${#string}
expr length $string
expr "$string" : '.*'
示例:
stringZ=abcABC123ABCabcecho ${#stringZ} # 15
echo $(expr length $stringZ) # 15
echo $(expr "$stringZ" : '.*') # 15
${#var}
字符串长度 (变量$var得字符个数) 。 对于 array 来说, ${#array} 表示的是数组中第一个元素的长度。
例外情况:
- ${#*} 和 ${#@} 表示位置参数的个数。
- 对于数组来说, ${#array[*]} 和 ${#array[@]} 表示数组中元素的个数。
匹配字符串开头的子串长度
语法:
expr match "$string" '$substring'
# $substring 是一个正则表达式.
expr "$string" : '$substring'
# $substring是一个正则表达式.
示例:
stringZ=abcABC123ABCabc
# |------|echo $(expr match "$stringZ" 'abc[A-Z]*.2') # 8
echo $(expr "$stringZ" : 'abc[A-Z]*.2') # 8
索引
语法:
expr index $string $substring
# 在字符串 $string 中所匹配到的 $substring 第一次所出现的位置
示例:
stringZ=abcABC123ABCabcecho $(expr index "$stringZ" C12) # 6 # C 字符的位置
echo $(expr index "$stringZ" 1c) # 3
# 'c' (in #3 position) matches before '1'.
提取子串
语法:
${string:position}
# 在 $string 中从位置 $position 开始提取子串.
# 如果 $string 是 "*" 或者 "@" , 那么将会提取从位置 $position 开始的位置参数.${string:position:length}
# 在 $string 中从位置 $position 开始提取 $length 长度的子串.
示例:
stringZ=abcABC123ABCabc
# 0123456789.....
# 0-based indexing.echo ${stringZ:0} # abcABC123ABCabc
echo ${stringZ:1} # bcABC123ABCabc
echo ${stringZ:7} # 23ABCabc
echo ${stringZ:7:3} # 23A# 提取子串长度为3.# 能不能从字符串的右边(也就是结尾)部分开始提取子串?
echo ${stringZ:-4} # abcABC123ABCabc
# 默认是提取整个字符串, 就象${parameter:-default}一样.
# 然而 . . . echo ${stringZ:(-4)} # Cabc
echo ${stringZ: -4} # Cabc
# 这样, 它就可以工作了.
# 使用圆括号或者添加一个空格可以"转义"这个位置参数.
如果 $string 参数是 "*"
或 "@"
, 那么将会从 $position 位置开始提取 $length 个位置参数, 但是由于可能没有 $length 个位置参数了,那么就有几个位置参数就提取几个位置参数。
echo ${*:2} # 打印出第2个和后边所有的位置参数.
echo ${@:2} # 同上.echo ${*:2:3} # 从第2个开始, 连续打印3个位置参数.#./t.sh 1 2 3 4 5 6
#2 3 4 5 6
#2 3 4 5 6
#2 3 4
语法:
expr substr $string $position $length
# 在 $string 中从 $position 开始提取 $length 长度的子串.expr match "$string" '\($substring\)'
# 从 $string 的开始位置提取 $substring, $substring 是正则表达式.expr "$string" : '\($substring\)'
# 从 $string 的开始位置提取 $substring , $substring 是正则表达式.
示例:
stringZ=abcABC123ABCabc
# =======
echo $(expr match "$stringZ" '\(.[b-c]*[A-Z]..[0-9]\)') # abcABC1
echo $(expr "$stringZ" : '\(.[b-c]*[A-Z]..[0-9]\)') # abcABC1
echo $(expr "$stringZ" : '\(.......\)') # abcABC1
# 上边的每个echo都打印出相同的结果.
语法:
expr match "$string" '.*\($substring\)'
# 从 $string 的结尾提取$substring, $substring 是正则表达式.
expr "$string" : '.*\($substring\)'
# 从 $string 的结尾提取 $substring, $substring 是正则表达式.
示例:
stringZ=abcABC123ABCabc
# ======echo $(expr match "$stringZ" '.*\([A-C][A-C][A-C][a-c]*\)') # ABCabc
echo $(expr "$stringZ" : '.*\(......\)') # ABCabc
子串削除
语法:
${string#substring}
# 从 $string 的开头位置截掉最短匹配的 $substring .
${string##substring}
# 从 $string 的开头位置截掉最长匹配的 $substring .
示例:
stringZ=abcABC123ABCabc
# |----|
# |----------|echo ${stringZ#a*C} # 123ABCabc
# 截掉'a'到'C'之间最短的匹配字符串.echo ${stringZ##a*C} # abc
# 截掉'a'到'C'之间最长的匹配字符串.
语法:
${string%substring}
# 从 $string 的结尾位置截掉最短匹配的 $substring .
${string%%substring}
# 从 $string 的结尾位置截掉最长匹配的 $substring.
示例:
stringZ=abcABC123ABCabc
# ||
# |------------|echo ${stringZ%b*c} # abcABC123ABCa
# 从$stringZ的结尾位置截掉'b'到'c'之间最短的匹配. echo ${stringZ%%b*c} # a
# 从$stringZ的结尾位置截掉'b'到'c'之间最长的匹配.
子串替换
语法:
${string/substring/replacement}
# 使用 $replacement 来替换第一个匹配的 $substring .${string//substring/replacement}
# 使用 $replacement 来替换所有匹配的 $substring .
示例:
stringZ=abcABC123ABCabc
echo ${stringZ/abc/xyz} # xyzABC123ABCabc# 使用'xyz'来替换第一个匹配的'abc'.echo ${stringZ//abc/xyz} # xyzABC123ABCxyz# 用'xyz'来替换所有匹配的'abc'.
语法:
${string/#substring/replacement}
# 如果 $substring 匹配 $string 的开头部分, 那么就用 $replacement 来替换 $substring .${string/%substring/replacement}
# 如果 $substring 匹配 $string 的结尾部分, 那么就用 $replacement 来替换 $substring.
示例:
stringZ=abcABC123ABCabcecho ${stringZ/#abc/XYZ} # XYZABC123ABCabc# 用'XYZ'替换开头的'abc'.echo ${stringZ/%abc/XYZ} # abcABC123ABCXYZ# 用'XYZ'替换结尾的'abc'.
(3) 参数替换
处理和(或)扩展变量
-
${parameter}
与 $parameter 相同, 也就是变量 parameter 的值。 -
${parameter-default}, ${parameter:-default}
${parameter-default} – 如果变量 parameter 没被声明, 那么就使用默认值。
${parameter:-default} – 如果变量 parameter 没被设置, 那么就使用默认值。 -
${parameter=default}, ${parameter:=default}
${parameter=default} – 如果变量 parameter 没声明, 那么就把它的值设为 default。
${parameter:=default} – 如果变量 parameter 没设置, 那么就把它的值设为 default。
这两种形式基本上是一样的。 只有在变量 $parameter 被声明并且被设置为 null 值的时候, 才会引起这两种形式的不同。 -
${parameter+alt_value}, ${parameter:+alt_value}
${parameter+alt_value} – 如果变量 parameter 被声明了, 那么就使用 alt_value , 否则就使用 null 字符串。
${parameter:+alt_value} – 如果变量 parameter 被设置了, 那么就使用 alt_value , 否则就使用 null 字符串。
这两种形式绝大多数情况下都一样。 只有在 parameter 被声明并且设置为 null 值的时候, 多出来的这个: 才会引起这两种形式的不同。 -
${parameter?err_msg}, ${parameter:?err_msg}
${parameter?err_msg} – 如果 parameter 已经被声明, 那么就使用设置的值, 否则打印 err_msg 错误消息。
${parameter:?err_msg} – 如果 parameter 已经被设置, 那么就使用设置的值, 否则打印 err_msg 错误消息。
这两种形式绝大多数情况都是一样的。 和上边所讲的情况一样, 只有在 parameter 被声明并设置为 null 值的时候, 多出来的:才会引起这两种形式的不同。
(4)指定变量的类型: 使用 declare 或者 typeset
declare 或者 typeset 内建命令(这两个命令是完全一样的)允许指定变量的具体类型。 在某些编程语言中, 这是指定变量类型的一种很弱的形式。 declare 命令是从 Bash 2.0 之后才被引入的命令。 typeset 也可以用在 ksh 的脚本中。
declare/typeset 选项
- -r 只读
declare -r var1
(declare -r var1 与 readonly var1 是完全一样的)
这和 C 语言中的 const 关键字一样, 都用来指定变量为只读。 如果你尝试修改一个只读变量的值,那么会产生错误信息。
- -i 整型
declare -i number
# 脚本将会把变量"number"按照整型进行处理。number=3
echo "Number = $number" # Number = 3number=three
echo "Number = $number" # Number = 0
# 脚本尝试把字符串"three"作为整数来求值(译者注: 当然会失败, 所以出现值为0)。
如果把一个变量指定为整型的话, 那么即使没有 expr 或者 let 命令, 也允许使用特定的算术运算。
n=6/3
echo "n = $n" # n = 6/3declare -i n
n=6/3
echo "n = $n" # n = 2
- -a 数组
declare -a indices
变量 indices 将被视为数组。
- -f 函数
declare -f
如果在脚本中使用declare -f, 而不加任何参数的话, 那么将会列出这个脚本之前定义的所有函数。
declare -f function_name
如果在脚本中使用declare -f function_name这种形式的话, 将只会列出这个函数的名字。
- -x export
declare -x var3
这句将会声明一个变量, 并作为这个脚本的环境变量被导出。
- -x var=$value
declare -x var3=373
declare 命令允许在声明变量类型的同时给变量赋值。
示例:
#!/bin/bashfunc1() {echo This is a function.
}declare -f # 列出前面定义的所有函数。
echodeclare -i var1 # var1是个整型变量。
var1=2367
echo "var1 declared as $var1"
var1=var1+1 # 整型变量的声明并不需要使用'let'命令。
echo "var1 incremented by 1 is $var1."
# 尝试修改一个已经声明为整型变量的值。
echo "Attempting to change var1 to floating point value, 2367.1."
var1=2367.1 # 产生错误信息, 并且变量并没有被修改。
echo "var1 is still $var1"echodeclare -r var2=13.36 # 'declare'允许设置变量的属性,#+ 同时给变量赋值。
echo "var2 declared as $var2" # 试图修改只读变量的值。
var2=13.37 # 产生错误消息, 并且从脚本退出。echo "var2 is still $var2" # 将不会执行到这行。exit 0 # 脚本也不会从此处退出。
(5)变量的间接引用
假设一个变量的值是第二个变量的名字。 那么我们如何从第一个变量中取得第二个变量的值呢? 比如,如果 a=letter_of_alphabet 并且 letter_of_alphabet=z , 那么我们能够通过引用变量 a 来获得 z 么? 这确实是可以做到的, 它被称为间接引用。 它使用 eval var1=\$$a 这种不平常的形式。
#!/bin/bash# ind-ref.sh: 间接变量引用.
# 访问一个以另一个变量内容作为名字的变量的值.(译者注: 怎么译都不顺)a=letter_of_alphabet # 变量"a"的值是另一个变量的名字.
letter_of_alphabet=zecho# 直接引用.
echo "a = $a" # a = letter_of_alphabet# 间接引用.
eval a=\$$a
echo "Now a = $a" # 现在 a = zecho# 现在, 让我们试试修改第二个引用的值.t=table_cell_3
table_cell_3=24
echo "\"table_cell_3\" = $table_cell_3" # "table_cell_3" = 24
echo -n "dereferenced \"t\" = "
eval echo \$$t # 解引用 "t" = 24
# 在这个简单的例子中, 下面的表达式也能正常工作么(为什么?).
# eval t=\$$t; echo "\"t\" = $t"echot=table_cell_3
NEW_VAL=387
table_cell_3=$NEW_VAL
echo "Changing value of \"table_cell_3\" to $NEW_VAL."
echo "\"table_cell_3\" now $table_cell_3"
echo -n "dereferenced \"t\" now "
eval echo \$$t
# "eval" 带有两个参数 "echo" 和 "\$$t" (与$table_cell_3等价)echo# (感谢, Stephane Chazelas, 澄清了上边语句的行为.)# 另一个方法是使用${!t}符号, 见"Bash, 版本2"小节的讨论. 45 # 也请参考 ex78.sh.exit 0
变量的间接引用到底有什么应用价值? 它给 Bash 添加了一种类似于 C 语言指针的功能, 比如, 在表格查找中的用法。
(6)$RANDOM: 产生随机整数
$RANDOM 是 Bash 的内部函数 (并不是常量), 这个函数将返回一个伪随机整数, 范围在 0 - 32767 之间。 它不应该被用来产生密匙。
#!/bin/bash
# 每次调用$RANDOM都会返回不同的随机整数.
# 一般范围为: 0 - 32767 (有符号的 16-bit整数).MAXCOUNT=10
count=1echo
echo "$MAXCOUNT random numbers:"
echo "-----------------"while [ "$count" -le $MAXCOUNT ] # 产生10 ($MAXCOUNT)个随机整数.
donumber=$RANDOMecho $numberlet "count += 1" # 增加计数.
done
echo "-----------------"# 如果你需要在特定范围内产生随机整数, 那么使用'modulo'(模)操作.(译者注: 事实上, 这不是一个非常 好的办法. 理由见man 3 rand)
# 取模操作会返回除法的余数.
RANGE=500echonumber=$RANDOM
let "number %= $RANGE"
# ^^
echo "Random number less than $RANGE --- $number"echo# 如果你需要产生一个大于某个下限的随机整数.
#+ 那么建立一个test循环来丢弃所有小于此下限值的整数. FLOOR=200number=0 #初始化
while [ "$number" -le $FLOOR ]
donumber=$RANDOM
done
echo "Random number greater than $FLOOR --- $number"
echo# 让我们对上边的循环尝试一个小改动, 如下:
# let "number = $RANDOM + $FLOOR"
# 这将不再需要那个while循环, 并且能够运行的更快.
# 但是, 这可能会产生一个问题, 思考一下是什么问题?
# 结合上边两个例子, 来在指定的上下限之间来产生随机数.
number=0 #initialize
while [ "$number" -le $FLOOR ]
donumber=$RANDOMlet "number %= $RANGE" # 让$number依比例落在$RANGE的范围内.
done
echo "Random number between $FLOOR and $RANGE --- $number"
echo# 产生二元值, 就是, "true" 或 "false" 两个值.
BINARY=2
T=1
number=$RANDOM
let "number %= $BINARY"
# 注意 let "number >>= 14" 将会给出一个更好的随机分配. #(译者注: 正如man页中提到的, 更 高位的随机分布更加平均)
#+ (右移14位将把所有的位全部清空, 除了第15位, 因为有符号, 第16位是符号位). #取模操作使用低位来 产生随机数会相对不平均)
if [ "$number" -eq $T ]
thenecho "TRUE"
elseecho "FALSE"
fi echo# 抛骰子.
SPOTS=6 # 模 6 给出的范围是 0 - 5.
# 加 1 会得到期望的范围
# 感谢, Paulo Marcel Coelho Aragao, 对此进行的简化.
die1=0
die2=0
# 是否让SPOTS=7会比加1更好呢? 解释行或者不行的原因?
# 每次抛骰子, 都会给出均等的机会.
let "die1 = $RANDOM % $SPOTS +1" # 抛第一次.
let "die2 = $RANDOM % $SPOTS +1" # 抛第二次.
# 上边的算术操作中, 哪个具有更高的优先级呢 --
#+ 模(%) 还是加法操作(+)?
let "throw = $die1 + $die2"
echo "Throw of the dice = $throw"
echo
exit
(7)双圆括号结构
与 let 命令很相似, ((…)) 结构允许算术扩展和赋值。 举个简单的例子, a=$(( 5 + 3 )), 将把变量 “a” 设为 “5 + 3” , 或者 8 。 然而, 双圆括号结构也被认为是在 Bash 中使用 C 语言风格变量操作的一种处理机制。
#!/bin/bash
# 使用((...))结构操作一个变量, C语言风格的变量操作.echo((a = 23)) # C语言风格的变量赋值, "="两边允许有空格.
echo "a (initial value) = $a"((a++)) # C语言风格的后置自加.
echo "a (after a++) = $a"((a--)) # C语言风格的后置自减.
echo "a (after a--) = $a"((++a)) # C语言风格的前置自加.
echo "a (after ++a) = $a"((--a)) # C语言风格的前置自减.
echo "a (after --a) = $a"echo########################################################
# 注意: 就像在C语言中一样, 前置或后置自减操作
#+ 会产生一些不同的副作用.n=1
let --n && echo "True" || echo "False" # False
n=1
let n-- && echo "True" || echo "False" # True# 感谢, Jeroen Domburg.
########################################################echo((t = a < 45 ? 7 : 11)) # C语言风格的三元操作.
echo "If a < 45, then t = 7, else t = 11."
echo "t = $t " # Yes!echo# ------------
# 复活节彩蛋!
# ------------
# Chet Ramey显然偷偷摸摸的将一些未公开的C语言风格的结构
#+ 引入到了Bash中 (事实上是从ksh中引入的, 这更接近些).
# 在Bash的文档中, Ramey将((...))称为shell算术运算,
#+ 但是它所能做的远远不止于此.
# 不好意思, Chet, 现在秘密被公开了.# 你也可以参考一些 "for" 和 "while" 循环中使用((...))结构的例子.# 这些只能够在Bash 2.04或更高版本的Bash上才能运行.exit 0
☆
相关文章:
Bash 学习摘录
文章目录 1、变量和参数的介绍(1)变量替换$(...) (2)特殊的变量类型export位置参数shift 2、引用(1)引用变量(2)转义 3、条件判断(1)条件测试结构(…...
GD32 MCU是如何进入中断函数的
用过GD32 MCU的小伙伴们都知道,程序是顺序执行的,但当有中断来的时候程序会跳转到中断函数,执行完中断函数后程序又继续回到原来的位置继续执行,那么你们知道MCU是如何找到中断函数入口的吗? 今天我们就以GD32F303系列…...
Ruby 循环
Ruby 循环 在编程中,循环是一种常用的控制结构,它允许我们重复执行一段代码多次。Ruby 作为一种灵活的编程语言,提供了多种循环方法,包括 while、until、for、each 和 loop 等。本文将详细介绍 Ruby 中的循环机制,并通…...
三字棋游戏(C语言详细解释)
hello,小伙伴们大家好,算是失踪人口回归了哈,主要原因是期末考试完学校组织实训,做了俄罗斯方块,后续也会更新,不过今天先从简单的三字棋说起 话不多说,开始今天的内容 一、大体思路 我们都知…...
H3CNE(计算机网络的概述)
1. 计算机网络的概述 1.1 计算机网络的三大基本功能 1. 资源共享 2. 分布式处理与负载均衡 3. 综合信息服务 1.2 计算机网络的三大基本类型 1.3 网络拓扑 定义: 网络设备连接排列的方式 网络拓扑的类型: 总线型拓扑: 所有的设备共享一…...
【极客日常】Golang一个的slice数据替换的bug排查
上周某天下班前,接到同事转来一个bug要排查,症状是代码重构之后某些业务效果不符合预期,由于代码重构人是笔者,于是blame到笔者这边。经过10min左右的排查和尝试后,解决了这个问题:既往逻辑没有改动&#x…...
HarmonyOS应用开发者高级认证,Next版本发布后最新题库 - 单选题序号3
基础认证题库请移步:HarmonyOS应用开发者基础认证题库 注:有读者反馈,题库的代码块比较多,打开文章时会卡死。所以笔者将题库拆分,单选题20个为一组,多选题10个为一组,题库目录如下,…...
UE4-光照重建
当我们拉入新的光源和模型到我们的场景中后,会产生这样的情况: Preview:预览 表示此时由于光照物体所产生的阴影都是预览级别的并不是真正的效果。 方法一: 或者也可以在世界大纲中选中我们的光源,然后将我们的光源改变为可以…...
【2024德国签证】留学面签问题汇总
在去交材料的时候,可能会被随机安排面试。这些面试问题一般都很简单,主要是测试你的基本英文交流能力。无需担心,签证官不会问太专业的问题,因为他们也不懂专业内容。到目前为止,没有一个博士生因为这个面试被拒签。毕…...
知识点大纲
学习方法 学习、整理笔记过程中,顺便整理出一个以问题为模版的大纲,到时候对着问题,就像是在和面试官讲解那样,相当于升级版的费曼学习法 除了看博客,问gpt外,亲自实验也是获取知识及加深印象的关键点 很…...
MySQL:库表操作
MySQL:库表操作 库操作查看创建字符编码集 删除修改备份 表操作创建查看删除修改 库操作 查看 查看存在哪些数据库: show databases;示例: 查看自己当前处于哪一个数据库: select database();示例: 此处由于我不处于任…...
8.3 End-to-end Data Protection (Optional)
8.3 End-to-end Data Protection (Optional) 为了提供从应用程序到NVM介质并返回到应用程序本身的稳健数据保护,可以使用端到端数据保护。如果启用了此可选机制,则将额外的保护信息(例如CRC)添加到逻辑块中,控制器和/或主机软件可以对其进行评估,以确定逻辑块的完整性。…...
python实现图像对比度增强算法
python实现直方图均衡化、自适应直方图均衡化、连接组件标记算法 1.直方图均衡化算法详解算法步骤公式Python 实现详细解释优缺点 2.自适应直方图均衡化算法详解算法步骤公式Python 实现详细解释优缺点 3.连接组件标记算法详解算法步骤8连通与4连通公式Python 实现详细解释优缺…...
【D3.js in Action 3 精译_020】2.6 用 D3 设置与修改元素样式 + 名人专访(Nadieh Bremer)+ 2.7 本章小结
当前内容所在位置 第一部分 D3.js 基础知识 第一章 D3.js 简介(已完结) 1.1 何为 D3.js?1.2 D3 生态系统——入门须知1.3 数据可视化最佳实践(上)1.3 数据可视化最佳实践(下)1.4 本章小结 第二章…...
GIT命令学习 二
📑打牌 : da pai ge的个人主页 🌤️个人专栏 : da pai ge的博客专栏 ☁️宝剑锋从磨砺出,梅花香自苦寒来 ☁️运维工程师的职责:监…...
LeetCode 150, 112, 130
文章目录 150. 逆波兰表达式求值题目链接标签思路代码 112. 路径总和题目链接标签思路代码 130. 被围绕的区域题目链接标签思路代码 150. 逆波兰表达式求值 题目链接 150. 逆波兰表达式求值 标签 栈 数组 数学 思路 本题很像 JVM 中的 操作数栈,当写出以下三行…...
c++应用网络编程之五Windows常用的网络IO模型
一、Windows的网络编程 其实对开发者而言,只有Windows和其它平台。做为一种普遍流行的图形OS,其一定会与类Linux的编程有着明显的区别,这点当然也会体现在网络编程上。Windows有着自己一套相对独立的上层Socket编程模型或者说框架࿰…...
PostgreSQL 中如何解决因大量并发删除和插入操作导致的索引抖动?
🍅关注博主🎗️ 带你畅游技术世界,不错过每一次成长机会!📚领书:PostgreSQL 入门到精通.pdf 文章目录 PostgreSQL 中如何解决因大量并发删除和插入操作导致的索引抖动一、理解索引抖动二、索引抖动的影响三…...
鑫创SSS1700USB音频桥芯片USB转IIS芯片
鑫创SSS1700支持IIC初始外部编(EEPROM选项),两线串行总线(I2C总线)用于外部MCU控制整个EEPROM空间可以通过MCU访问用于主机控制同步的USB HID外部串行EEPROM(24C02~24C16)接口,用于客户特定的USB视频、PID、…...
计算机视觉发展历程
文章目录 前言一、发展历程1)、萌芽期(1960s-1970s)2)、基础发展期(1980s)3)、系统开发期(1990s-2000s)4)、深度学习兴起期(2010s)5&a…...
从安装Node到TypeScript到VsCode的配置教程
从安装Node到TypeScript到VsCode的配置教程 1.下载Node安装包, 链接 2.双击安装包,选择安装路径,如下: 3.一直点击下一步,直至安装结束即可: 这个时候,node会默认配置好环境变量,并且…...
Jackson详解
文章目录 一、Jackson介绍二、基础序列化和反序列化1、快速入门2、序列化API3、反序列化API4、常用配置 三、常用注解1、JsonProperty2、JsonAlias3、JsonIgnore4、JsonIgnoreProperties5、JsonFormat6、JsonPropertyOrder 四、高级特性1、处理泛型1.1、反序列化List泛型1.2、反…...
【算法】字符串
快乐的流畅:个人主页 个人专栏:《算法神殿》《数据结构世界》《进击的C》 远方有一堆篝火,在为久候之人燃烧! 文章目录 引言一、最长公共前缀二、最长回文子串三、二进制求和四、字符串相乘 引言 字符串题,大多数是模…...
Python酷库之旅-第三方库Pandas(037)
目录 一、用法精讲 116、pandas.Series.div方法 116-1、语法 116-2、参数 116-3、功能 116-4、返回值 116-5、说明 116-6、用法 116-6-1、数据准备 116-6-2、代码示例 116-6-3、结果输出 117、pandas.Series.truediv方法 117-1、语法 117-2、参数 117-3、功能 …...
iOS 左滑返回事件的控制
0x00 视图结构 1-根视图 1.1-控制器A 1.1.1-控制器B 1.1.1.1-控制器C 0x01 控制 通过设置 self.navigationController.interactivePopGestureRecognizer.enabled 为 YES 或 NO 来控制当面界面,是否能左滑返回 在 控制器B 的生命周期方法内,设置属性 s…...
= null 和 is null;SQL中关于NULL处理的4个陷阱;三值逻辑
一、概述 1、NULL参与的所有的比较和算术运算符(>,,<,<>,<,>,,-,*,/) 结果为unknown; 2、unknown的逻辑运算(AND、OR、NOT)遵循三值运算的真值表; 3、如果运算结果直接返回用户,使用NULL来标识unknown 4、如…...
拖拽上传(预览图片)
需求 点击上传图片,或直接拖拽图片到红色方框里面也可上传图片,上传后预览图片 效果 实现 <!DOCTYPE html> <html lang"zh-cn"><head><meta charset"UTF-8"><meta name"viewport" content&…...
Oracle 12c新特性 In-Memory Column Store
Oracle 12c引入了一项重要的特性——In-Memory Column Store(简称IM或In-Memory),这一特性极大地提升了数据库在处理分析型查询时的性能。以下是关于Oracle 12c In-Memory特性的详细介绍: 一、基本概念 In-Memory Column Store&…...
【数据结构】二叉树———Lesson2
Hi~!这里是奋斗的小羊,很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~~ 💥💥个人主页:奋斗的小羊 💥💥所属专栏:C语言 🚀本系列文章为个人学习…...
mongodb数据导出与导入
一、先去检查mongodump mongodump --version 如果报 mongodump version: built-without-version-string 或者其他的较老的版本,直接去下载最新的【传送门】 【以Ubuntu18.04为例】 安装工具 假设你下载的是 .tgz 文件(适用于 Linux 系统)&am…...
网站建设和网站开发/seo关键词外包公司
今天的煤矿跟以前最大的区别是什么?答案可以有很多,但有一个变化非常具有代表性:这是一个女孩儿们开始走进煤矿、走向生产一线的时代。以前的煤矿,当然是有女性身影的,她们或许是食堂里做饭的大姐,在某个场…...
网页升级访问新区域/许昌正规网站优化公司
Zotero安装过程 Zotero官方下载链接:https://www.zotero.org/,目前应该是可以直接访问下载的。另外别忘了一起把浏览器的插件也安装好。 顺便注册一个同步账号,方便在其他移动端访问。注册好后,在Zotero中点击左上角“编辑”-“首…...
最牛的视频网站建设/软文营销的作用有哪些
http://www.169it.com/article/3215620760.html http://www.cnblogs.com/sharpfeng/archive/2012/09/18/2691096.html 在C的STL库中,要实现排序可以 通过将所有元素保存到vector中,然后通过sort算法来排序,也可以通过multimap实现在插入元素的…...
ecshop 网站标题修改/免费的网站域名查询565wcc
如新语法的字面含义,NOWAIT表示当无法获取到锁时直接返回错误,而不是等待;SKIP LOCKED表示忽略那些已经被其他session占有行锁的记录。下面看测试: 测试 一 session 1 : mysql> select * from t; ---- | a | ---- | 42 | | …...
上海网站如何制作/昆明百度搜索排名优化
准备过程 先说说我自己的情况,我2016先在蚂蚁实习了将近三个月,然后去了我现在的老东家,三年多工作经验,可以说毕业后就一直老老实实在老东家打怪升级,虽说有蚂蚁的实习经历,但是因为时间太短,…...
网站建设有利点/东莞seo技术
6242: LHC的二进制升级版 时间限制:1秒内存限制:128MBSpecial Judge提交:6正确:3题目描述 在发现了3的二进制特殊性质后,LHC认为形如1、3、7、15......2n−1之类的数具有共通的性质。但是他太懒了,请你帮他验证结论吧。现在,LHC要求你在1s内判…...