作者:じ☆ve不哭
发布时间:2023-08-21T09:43:47
Bash 进阶 P101
变量名($名称) | 意思 |
---|---|
BASH | Bash 的二进制程序文件的路径 |
BASH_ENV | Bash的启动文件 |
BASH_SUBSHELL | 提示子shell的层次 |
BASH_VERSINFO[n] | 6个元素的数组, 它包含了所安装的Bash的版本信息 |
BASH_VERSION | Bash版本号 |
DIRSTACK | 在目录栈中最顶端的值 |
EDITOR | 脚本所调用的默认编辑器, 通常情况下是vi或者是emacs. |
EUID | "有效"用户ID |
FUNCNAME | 当前函数的名字 |
GLOBIGNORE | 一个文件名的模式匹配列表 |
GROUPS | 目前用户所属的组 |
HOME | 用户的home目录, 一般是 /home/username |
HOSTNAME | 在一个初始化脚本中, 在系统启动的时候分配一个系统名字 |
$HOSTTYPE | 主机类型 |
IFS | 内部域分隔符 决定Bash在解释字符串时如何识别域, 或者单词边界. |
IGNOREEOF | 忽略EOF: 告诉shell在log out之前要忽略多少文件结束符(control-D) |
LC_COLLATE | 常在 .bashrc 或 /etc/profile 中设置, 这个变量用来控制文件名扩展和模式匹配的展开顺序 |
LC_CTYPE | 来控制通配(globbing)和模式匹配中的字符串解释 |
LINENO | 自身在脚本中所在的行号 |
MACHTYPE | 机器类型 |
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 PS4 | 第几条提示符 |
PWD | 工作目录(你当前所在的目录) 与内建命令pwd作用相同 |
REPLY | 当没有参数变量提供给read命令的时候, 这个变量会作为默认变量提供给read命令. |
SECONDS | 脚本已经运行的时间 |
SHELLOPTS | hell中已经激活的选项的列表, 这是一个只读变量 |
SHLVL | Shell级别, 就是Bash被嵌套的深度. 如果是在命令行中, 那么$SHLVL为1, 如果在脚本中那么$SHLVL为2 |
TMOUT | 如果 $TMOUT 环境变量被设置为非零值 time 的话, 那么经过 time 秒后, shell提示符将会超时. 这将 会导致登出(logout). |
UID | 用户ID号 当前用户的用户标识号, 记录在 /etc/passwd 文件中 |
$0 , $1 , $2 | 位置参数, 从命令行传递到脚本, 或者传递给函数 或者set给变量 |
$# $* $@ |
命令行参数 或者位置参数的个数 所有的位置参数都被看作为一个单词 与$*相同, 但是每个参数都是一个独立的引用字符串 |
$- $! $_ $? $$ |
传递给脚本的标记 运行在后台的最后一个作业的PID(进程ID) 之前执行的命令的最后一个参数的值. 命令, 函数, 或者是脚本本身的退出状态码 脚本自身的进程ID. |
#!/bin/bash
# $IFS 处理空白与处理其他字符不同.
output_args_one_per_line()
{
for arg
do echo "[$arg]"
done
}
echo; echo "IFS=\" \""
echo "-------"
IFS=" "
var=" a b c "
output_args_one_per_line $var #
output_args_one_per_line `echo " a b c "`
#
# [a]
# [b]
# [c]
echo; echo "IFS=:"
echo "-----"
IFS=:
var=":a::b:c:::" # 与上边一样, 但是用" "替换
了":".
output_args_one_per_line $var
#
# []
# [a]
# []
# [b]
# [c]
# []
# []
# []
# 同样的事情也会发生在awk的"FS"域中.
echo
exit 0
#!/bin/bash
# reply.sh
# REPLY是提供给'read'命令的默认变量.
echo
echo -n "What is your favorite vegetable? "
read
echo "Your favorite vegetable is $REPLY."
# 当且仅当没有变量提供给"read"命令时,
#!/bin/bash
# timed-input.sh
# TMOUT=3 在新一些的Bash版本上也能运行的很好.
TIMELIMIT=3 # 这个例子中设置的是3秒. 也可以设置为其他的时间值.
PrintAnswer()
{
if [ "$answer" = TIMEOUT ]
then
echo $answer
else # 别和上边的例子弄混了.
echo "Your favorite veggie is $answer"
kill $! # 不再需要后台运行的TimerOn函数了, kill了吧.
# $! 变量是上一个在后台运行的作业的PID.
fi
}
TimerOn()
{
sleep $TIMELIMIT && kill -s 14 $$ &
# 等待3秒, 然后给脚本发送一个信号.
}
Int14Vector()
{
answer="TIMEOUT"
PrintAnswer
exit 14
}
trap Int14Vector 14 # 定时中断(14)会暗中给定时间限制.
echo "What is your favorite vegetable "
TimerOn
read answer
PrintAnswer
# 无可否认, 这是一个定时输入的复杂实现,
#+ 然而"read"命令的"-t"选项可以简化这个任务.
# 参考后边的"t-out.sh".
# 如果你需要一个真正优雅的写法...
#+ 建议你使用C或C++来重写这个应用,
#+ 你可以使用合适的函数库, 比如'alarm'和'setitimer'来完成这个任务.
exit 0
#!/bin/bash
# t-out.sh
# 从"syngin seven"的建议中得到的灵感 (感谢).
TIMELIMIT=4 # 4秒
read -t $TIMELIMIT variable <&1
# ^^^
# 在这个例子中, 对于Bash 1.x和2.x就需要"<&1"了,
# 但是Bash 3.x就不需要.
echo
if [ -z "$variable" ] # 值为null?
then
echo "Timed out, variable still unset."
else
echo "variable = $variable"
fi
exit 0
#!/bin/bash
# arglist.sh
# 多使用几个参数来调用这个脚本, 比如"one two three".
E_BADARGS=65
if [ ! -n "$1" ]
then
echo "Usage: `basename $0` argument1 argument2 etc."
exit $E_BADARGS
fi
echo
index=1 # 起始计数.
echo "Listing args with \"\$*\":"
for arg in "$*" # 如果"$*"不被""引用,那么将不能正常地工作.
do
echo "Arg #$index = $arg"
let "index+=1"
done # $* 将所有的参数看成一个单词.
echo "Entire arg list seen as single word."
echo
index=1 # 重置计数(译者注: 从1开始).
# 如果你写这句会发生什么?
echo "Listing args with \"\$@\":"
for arg in "$@"
do
echo "Arg #$index = $arg"
let "index+=1"
done # $@ 把每个参数都看成是单独的单词.
echo "Arg list seen as separate words."
echo
index=1 # 重置计数(译者注: 从1开始).
echo "Listing args with \$* (unquoted):"
for arg in $*
do
echo "Arg #$index = $arg"
let "index+=1"
done # 未引用的$*将会把参数看成单独的单词.
echo "Arg list seen as separate words."
exit 0
#!/bin/bash
# 使用 ./scriptname 1 2 3 4 5 来调用这个脚本
echo "$@" # 1 2 3 4 5
shift
echo "$@" # 2 3 4 5
shift
echo "$@" # 3 4 5
# 每次"shift"都会丢弃$1.
# "$@" 将包含剩下的参数.
expr 介绍
将表达式的值列印到标准输出,分隔符下面的空行可提升算式优先级。 可用的表达式有:
ARG1 | ARG2 若ARG1 的值不为0 或者为空,则返回ARG1,否则返回ARG2
ARG1 & ARG2 若两边的值都不为0 或为空,则返回ARG1,否则返回 0
ARG1 < ARG2 ARG1 小于ARG2 ARG1 <= ARG2 ARG1 小于或等于ARG2 ARG1 = ARG2 ARG1 等于ARG2 ARG1 != ARG2 ARG1 不等于ARG2 ARG1 >= ARG2 ARG1 大于或等于ARG2 ARG1 > ARG2 ARG1 大于ARG2
ARG1 + ARG2 计算 ARG1 与ARG2 相加之和 ARG1 - ARG2 计算 ARG1 与ARG2 相减之差
ARG1 * ARG2 计算 ARG1 与ARG2 相乘之积 ARG1 / ARG2 计算 ARG1 与ARG2 相除之商 ARG1 % ARG2 计算 ARG1 与ARG2 相除之余数
字符串 : 表达式 定位字符串中匹配表达式的模式
match 字符串 表达式 等于"字符串 :表达式" substr 字符串 偏移量 长度 替换字符串的子串,偏移的数值从 1 起计 index 字符串 字符 在字符串中发现字符的地方建立下标,或者标0 length 字符串 字符串的长度
- 记号 将记号解析为字符串,即使它是一个类似"match"或 运算符"/"那样的关键字
( 表达式 ) 表达式的值
请注意有许多运算操作符都可能需要由 shell 先实施转义。 如果参与运算的 ARG 自变量都是数字,比较符就会被视作数学符号,否则就是多义的。 模式匹配会返回""和""之间被匹配的子字符串或空(null);如果未使用""和"", 则会返回匹配字符数量或是 0。
若表达式的值既不是空也不是 0,退出状态值为 0;若表达式的值为空或为 0, 退出状态值为 1。如果表达式的句法无效,则会在出错时返回退出状态值 3。
字符串长度
- ${#string}
- expr length $string
- expr "$string" : '.*
stringZ=abcABC123ABCabc
echo ${#stringZ} # 15
echo `expr length $stringZ` # 15
echo `expr "$stringZ" : '.*'` # 15
匹配字符串开头的子串长度
- expr match "$string" '$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
stringZ=abcABC123ABCabc
echo `expr index "$stringZ" C12` # 6
# C 字符的位置.
echo `expr index "$stringZ" 1c` # 3
# 'c' (in #3 position) matches before '1'.
提取子串
- ${string:position 从位置$position 开始提取子串}
- ${string:position:length 从位置 $position 开始提取 $length 长度的子串.}
- expr substr $string $position $length 在 $string 中从 $position 开始提取 $length 长度的子串.
- expr match "$string" '\($substring\)'
- expr "$string" : '\($substring\)'
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
# 这样, 它就可以工作了.
# 使用圆括号或者添加一个空格可以"转义"这个位置参数.
stringZ=abcABC123ABCabc
2 # 123456789......
3 # 以1开始计算.
4
5 echo `expr substr $stringZ 1 2` # ab
6 echo `expr substr $stringZ 4 3` # ABC
子串削除
- ${string#substring 从 $string 的 开头 位置截掉 最短 匹配的 $substring .}
- ${string##substring 从 $string 的 开头 位置截掉 最长 匹配的 $substring .}
- ${string%substring 从 $string 的 结尾 位置截掉 最短 匹配的 $substring .}
- ${string%%substring 从 $string 的 结尾 位置截掉 最长 匹配的 $substring .}
stringZ=abcABC123ABCabc
# |----|
# |----------|
echo ${stringZ#a*C} # 123ABCabc
# 截掉'a'到'C'之间最短的匹配字符串.
echo ${stringZ##a*C} # abc
# 截掉'a'到'C'之间最长的匹配字符串.
stringZ=abcABC123ABCabc
# ||
# |------------|
echo ${stringZ%b*c} # abcABC123ABCa
# 从$stringZ的结尾位置截掉'b'到'c'之间最短的匹配.
echo ${stringZ%%b*c} # a
# 从$stringZ的结尾位置截掉'b'到'c'之间最长的匹配.
#!/bin/bash
# getopt-simple.sh
getopt_simple()
{
echo "getopt_simple()"
echo "Parameters are '$*'"
until [ -z "$1" ]
do
echo "Processing parameter of: '$1'"
if [ ${1:0:1} = '/' ]
then
tmp=${1:1} # 去掉开头的'/' . . .
parameter=${tmp%%=*} # 提取参数名.
value=${tmp##*=} # 提取参数值.
echo "Parameter: '$parameter', value: '$value'"
eval $parameter=$value
fi
shift
done
}
# 把所有选项传给函数getopt_simple().
getopt_simple $*
echo "test is '$test'"
echo "test2 is '$test2'"
exit 0
---
sh getopt_example.sh /test=value1 /test2=value2
Parameters are '/test=value1 /test2=value2'
Processing parameter of: '/test=value1'
Parameter: 'test', value: 'value1'
Processing parameter of: '/test2=value2'
Parameter: 'test2', value: 'value2'
test is 'value1'
test2 is 'value2'
子串替换
- ${string/substring/replacement 替换第一个匹配}
- ${string//substring/replacement 替换第所有匹配}
- ${string/#substring/replacement 替换开头匹配}
- ${string/%substring/replacement 替换结尾匹配}
stringZ=abcABC123ABCabc
echo ${stringZ/abc/xyz} # xyzABC123ABCabc
echo ${stringZ//abc/xyz} # xyzABC123ABCxyz
echo ${stringZ/#abc/XYZ} # XYZABC123ABCabc
echo ${stringZ/%abc/XYZ} # abcABC123ABCXYZ
#!/bin/bash
# substring-extraction.sh
String=23skidoo1
# 012345678 Bash
# 123456789 awk
# 注意不同的字符串索引系统:
# Bash的第一个字符是从'0'开始记录的.
# Awk的第一个字符是从'1'开始记录的.
echo ${String:2:4} # 位置 3 (0-1-2), 4 个字符长
# skid
# awk中等价于${string:pos:length}的命令是substr(string,pos,length).
echo | awk '
{ print substr("'"${String}"'",3,4) # skid
}
'
# 使用一个空的"echo"通过管道传递给awk一个假的输入,
#+ 这样就不必提供一个文件名给awk.
exit 0
处理和(或)扩展变量
- ${parameter 与 $parameter 相同, 也就是变量 parameter 的值}
- ${parameter-default 如果变量parameter没被声明, 那么就使用默认值}
- ${parameter:-default 如果变量parameter没被设置, 那么就使用默认值.}
- ${parameter=default , ${parameter:=default} 如果变量parameter没被设置, 那么就使用默认值.}}
- ${parameter+alt_value , ${parameter:+alt_value} parameter没声明或者设置, 么就使用null ,否则使用alt_value.}}
- ${parameter?err_msg 未声明 打印 err_msg}
- ${parameter:?err_msg未设置 打印 err_msg}
#!/bin/bash
# param-sub.sh
# 一个变量是否被声明或设置,
#+ 将会影响这个变量是否使用默认值,
#+ 即使这个变量值为空(null).
username0=
echo "username0 has been declared, but is set to null."
echo "username0 = ${username0-`whoami`}"
# 不会有输出.
echo
echo username1 has not been declared.
echo "username1 = ${username1-`whoami`}"
# 将会输出默