前言
Bash 是 Unix shell 的一种,本文讨论的是 Bash,而不一定是/bin/sh 所链接的那个 shell。
这里出现的所有代码片段,默认在顶上都添加了#!/bin/bash。
1. 严格意义上的 Bash 变量类型
Bash 变量只有两种类型,字符串和数组。
不过从严格意义上,Bash 没有变量类型。Bash 中的变量,在运行的时候会被展开成其对应的值(字符串)。你可以把它看做 C/C++中的宏定义,或者一些模板语言中的占位符。
一般情况下,变量通过=赋值,注意=两边不要留空格。
要想访问变量,只需在变量名前面添加$,解释器就会对它进行展开,养成加{}的好习惯。如果该变量并不存在,解释器会把它展开成“”。
who=spacewander
echo $me
echo $who
2. 命令行参数
我们可以在执行 Shell 脚本时,向脚本传递参数,脚本内获取参数的格式为:$n。n 代表一个数字,1 为执行脚本的第一个参数,2 为执行脚本的第二个参数,以此类推……
注意:$0获取的脚本的名字(其实就是其他语言中的第 0 个参数)
在 Bash 中,使用$1可以获取命令行输入的第一个参数,$2可以获取命令行输入的第 2 个参数,$3可以获取命令行输入的第......
你看,10000 的用法就这么交代完了。Bash 还是挺有逻辑的嘛。
$@获取所有的参数,$#获取参数的数目。
@和#这两个符号,前者表示全部参数,后者表示参数的数目。
| 参数处理 | 说明 |
|---|---|
| $n | 第几个参数,n 代表一个数字,1 即第一个参数,依次类推 |
$# | 传递到脚本的参数个数 |
| $* | 以一个单字符串显示所有向脚本传递的参数。 如"1 n"的形式输出所有参数。 |
| $$ | 脚本运行的当前进程 ID 号 |
| $! | 后台运行的最后一个进程的 ID 号 |
| $@ | 与@"用「"」括起来的情况、以"2" … "$n" 的形式输出所有参数。 |
| $- | 显示 Shell 使用的当前选项,与set 命令功能相同。 |
| $? | 显示最后命令的退出状态。0 表示没有错误,其他任何值表明有错误。 |
3. 数组和关联数组
Bash 中可以使用两种容器。
一种是数组,另一种是关联数组,类似于其他语言中的 Map/Hash/Dict。
声明数组的常用语法: declare -a ARY或者ARY=(1 2 3)
声明关联数组的唯一语法: declare -A MAP
赋值的语法:
直接ARY[N]=VALUE,N 可以是数字索引也可以是键。关联数组可以使用MAP=([x]=a [y]=b)进行多项赋值,注意这是赋值的语句而不是声明。
亲测数组中的索引不一定要按顺序来,你可以先给 2 和 3 上的元素赋值。(同样算是弱类型的 Javascript 也支持这种无厘头赋值,这算通病么?)
往现有数组批量添加元素:
ARY+=(a b c)
MAP+=([a]=1 [b]=2)
取值:
${ARY[INDEX]}
${MAP[KEY]}
注意花括号的使用
${A[@]}` 展开成所有的变量,而获取数组长度使用 `${#A[@]}
切片:
${ARY[@]:N:M}
N 是 offset 而 M 是 length
返回索引,相当于 keys():
${!MAP[@]}
试试下面的代码:
declare -a ARY
declare -A MAP
MAP+=([a]=1 [b]=2)
ARY+=(a b c)
echo ${ARY[1]}
echo ${MAP[a]}
echo "${ARY[@]}"
echo "${MAP[@]}"
echo "${ARY[@]:0:1}"
echo ${#ARY[@]}
echo "${!MAP[@]}"
ARY[4]=a
echo ${ARY[@]}
echo ${ARY[3]}
4. 变量(字符串)变换
Bash 中的变量变换,大体是${变量[操作符]}的形式
4.1 大小写变换
HI=HellO
echo "$HI" # HellO
echo ${HI^} # HellO
echo ${HI^^} # HELLO
echo ${HI,} # hellO
echo ${HI,,} # hello
echo ${HI~} # hellO
echo ${HI~~} # hELLo
^大写,,小写, ~大小写切换
重复一次只修改首字母,重复两次则应用于所有字母。
混着用会怎样?
echo ${HI^,^} # HellO
看来是不行的 ×_×
4.2 移除匹配的字符串
%xx 从后往前,开始匹配,移除匹配的内容
%%xx 跟上面的差不多,不过这是贪婪匹配
#xx 从前往后,开始匹配,移除匹配的内容
##xx 跟上面的差不多,不过这是贪婪匹配
这个比较难理解,不过看下面几个例子应该能明白了。
FILENAME=/home/spacewander/param.sh
echo ${FILENAME%/*} # /home/spacewander
echo ${FILENAME%%/*} #
echo ${FILENAME#*/} # home/spacewander/param.sh
echo ${FILENAME##*/} # param.sh
4.3 查找并替换
/MATCH/VALUE 替换第一个匹配的内容。
//MATCH/VALUE 替换匹配的内容
echo ${FILENAME/home/office} # /office/spacewander/param.sh
echo ${FILENAME//s/S} # /home/Spacewander/param.Sh
4.4 其它字符串操作
获取变量(字符串)长度:
${#FILENAME}
字符串切片:跟数组切片是同样的语法:
${STR:offset:len}
你还可以使用负数作为 offset,这时候就是从后往前算起。注意负数要用括号括起来,避免冲突。
TEXT=这个程序充满了BUG!
echo ${TEXT:0:8}
echo ${TEXT:4}
echo ${TEXT:(-4)}
4.5 关于变量,其它的内容
Bash 中有一项特性,你可以方便地检查某个变量是否设置了,如果没有设置,就赋予一个默认值。尤其在处理环境变量的时候,这项特性会让你感到欣慰。
语法是${VAR:=VALUE}或者${VAR=VALUE}。此外,还有一个相似的语法,${VAR:-VALUE}和${VAR-VALUE}。
下面展示下两者的区别
# expand to default variable
echo ${NULL-"Not null"} # Not null
echo ${NULL} #
# set default variable
echo ${NIL="Not nil"} # Not nil
echo ${NIL} # Not nil
可以看出,前者只是当变量不存在时,展开成指定的值。而后者在变量不存在时,将变量的值设置为指定值。
最后介绍一个,当目标变量不存在时,指定报错信息的语法。
echo ${TARGET?Not Found} # 当$TARGET不存在时,显示TARGET: Not Found,并结束程序。
【星猿杂谈】:在这里我们共同探索科技新趋势,分享积累的点滴,从编程语言到系统架构,从人工智能到高性能计算,我们追求技术的进步,同时珍视分享的力量。欢迎关注我们,在技术的精彩世界中一起遨游,发现更多未知!