Bash 是 Unix shell 的一种,本文讨论的是 Bash,而不一定是/bin/sh 所链接的那个 shell。
这里出现的所有代码片段,默认在顶上都添加了#!/bin/bash
。
Bash 变量只有两种类型,字符串和数组。
不过从严格意义上,Bash 没有变量类型。Bash 中的变量,在运行的时候会被展开成其对应的值(字符串)。你可以把它看做 C/C++中的宏定义,或者一些模板语言中的占位符。
一般情况下,变量通过=
赋值,注意=
两边不要留空格。
要想访问变量,只需在变量名前面添加$
,解释器就会对它进行展开,养成加{}的好习惯。如果该变量并不存在,解释器会把它展开成“”。
who=spacewander
echo $me
echo $who
我们可以在执行 Shell 脚本时,向脚本传递参数,脚本内获取参数的格式为:$n。n 代表一个数字,1 为执行脚本的第一个参数,2 为执行脚本的第二个参数,以此类推……
注意:$0
获取的脚本的名字(其实就是其他语言中的第 0 个参数)
在 Bash 中,使用$1
可以获取命令行输入的第一个参数,$2
可以获取命令行输入的第 2 个参数,$3
可以获取命令行输入的第…
你看,$1到$10000 的用法就这么交代完了。Bash 还是挺有逻辑的嘛。
$@
获取所有的参数,$#
获取参数的数目。
@
和#
这两个符号,前者表示全部参数,后者表示参数的数目。
参数处理 | 说明 |
---|---|
$n | 第几个参数,n 代表一个数字,$0表示命令本身,$1 即第一个参数,依次类推 |
$# |
传递到脚本的参数个数 |
$* | 以一个单字符串显示所有向脚本传递的参数。 如"$*“用「”」括起来的情况、以"$1 $2 … $n"的形式输出所有参数。 |
$$ | 脚本运行的当前进程 ID 号 |
$! | 后台运行的最后一个进程的 ID 号 |
$@ | 与 ∗ 相同,但是使用时加引号,并在引号中返回每个参数。如 " *相同,但是使用时加引号,并在引号中返回每个参数。 如" ∗相同,但是使用时加引号,并在引号中返回每个参数。如"@“用「”」括起来的情况、以"$1" “$2” … “$n” 的形式输出所有参数。 |
$- | 显示 Shell 使用的当前选项,与set 命令功能相同。 |
$? | 显示最后命令的退出状态。0 表示没有错误,其他任何值表明有错误。 |
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]}
Bash 中的变量变换,大体是${变量[操作符]}的形式
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
看来是不行的 ×_×
%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
/MATCH/VALUE
替换第一个匹配的内容。
//MATCH/VALUE
替换匹配的内容
echo ${FILENAME/home/office} # /office/spacewander/param.sh
echo ${FILENAME//s/S} # /home/Spacewander/param.Sh
获取变量(字符串)长度:
${#FILENAME}
字符串切片:跟数组切片是同样的语法:
${STR:offset:len}
你还可以使用负数作为 offset,这时候就是从后往前算起。注意负数要用括号括起来,避免冲突。
TEXT=这个程序充满了BUG!
echo ${TEXT:0:8}
echo ${TEXT:4}
echo ${TEXT:(-4)}
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,并结束程序。
【星猿科技】:在这里我们共同探索科技新趋势,分享积累的点滴,从人工智能到高性能计算,我们追求技术的进步,同时珍视分享的力量。欢迎关注我们,在科技与影视的精彩世界中一起遨游,发现更多未知!