特殊变量
获取所有参数:
-
$@
:将每个参数视为独立个体(可用于for循环) -
$*
:将所有参数视为一个整体 - 参考:Shell $*和$@的区别
$#
参数个数
$$
当前进程的id
-
当前环境中执行
. <.sh>
或source <.sh>
,可以继承当前环境的变量,$$
不变 -
使用
sh
,bash
或直接运行脚本./xx.sh
,都无法继承当前环境的变量,新的$$
数组
a=(1 2 3)
用空格分割
下标访问:${a[$i]}
-
bash
:下标从0开始 -
zsh
:下标从1开始
Bash参数
脚本第一行#!<shell path> [options]
指定用哪个shell来执行该脚本,常用选项(options)如下:
-e
:表示任意指令返回非真值(非0值)时结束脚本,写作#!/bin/bash -e
更多选项参考bash -c "help set"
,online man: set(1p)更详细
if
if
本质上是在判断后续命令的返回值:0为真,非0为假
true
和false
是两个命令,true
返回0,false
返回1
if ls; then echo 1; fi # 真
if return 1; then echo 1; fi # 假
if sl; then echo 1; fi # 直接报错 command not found: sl
if true; then echo 1; fi # 真
if false; then echo 1; fi # 假
变量
shell变量本质上就是宏替换,可以将命令赋给一个变量,然后通过$
+变量名来执行命令
var=ls # z='ls' z="ls" 都是一样
$var # 执行 ls
所以:可以将true
或false
赋给一个变量,然后放在if
后面进行判断
var=true
if $var; then echo 1; fi # 真
var=false
if $var; then echo 1; fi # 假
双引号
bash
中的所有变量最好都用双引号括起来
在打印一个变量时,如果含有空白字符(空格、制表、换行等),通常会用双引号括起来,否则会被shell
按通配符进行解析
echo `ls -l` # 无换行
echo "`ls -l`" # 正常显示换行
Outside of double quotes,
$var
takes the value ofvar
, splits it into whitespace-delimited parts, and interprets each part as a glob (wildcard) pattern. Unless you want this behavior, always put$var
inside double quotes:"$var"
.不用双引号的话,变量会被拆分为多个部分(以空白字符为分割),每个部分被当作一个通配符(wildcard)进行解析
参考:
条件表达式
条件表达式主要有几种形式:ref
test EXPRESSION
[ EXPRESSION ]
[[ EXPRESSION ]]
(( EXPRESSION ))
[ 和 test
[
is another name for the traditionaltest
command.
关于if [ EXPRESSION ]
,左右方括号必须要隔空格的原因是:Shell将[
当作一条指令
which [
[: shell built-in command
whereis [
[: /usr/bin/[ /usr/share/man/man1/[.1.gz
ls -l /usr/bin/\[
-rwxr-xr-x 1 root root 59736 Sep 5 2019 '/usr/bin/['
# 可以看到'['是一个可执行文件
因此,也可以直接在交互Shell中测试[ EXPRESSION ]
的返回值($?
)
由于&&
和||
被Shell用于连接两条命令,因此,[ EXPRESSION ]
中出现&&
和||
时,会被认为是第二条指令,然后报错找不到]
[ 1 && 2 ] # False(返回值非0)
[: ']' expected # 报错
[ 1 ] && [ 2 ] # True(返回值为0)
[[
[[
是test
命令的一种改版,可以使用&&
和||
正则匹配:使用=~
来正则地比较字符串(好像只用=
也支持正则),字符串在左,正则模式在右
((
主要用于算数运算,支持C-style的自增自减(++/–)
The Double-Parentheses Construct
a=$(( 3 + 5 )) # shell里面这种‘a’和‘=’分开的话,一般情况下a会被当成指令
(( a++ ))
echo $a # 9
test 操作符
更多参见man bash
的CONDITIONAL EXPRESSIONS章节
-
字符串
-z
字符串长度为0返回true-n
字符串长度不为0返回true -
文件
-e
文件存在-d
文件存在&是目录-f
文件存在&是普通文件(非目录或设备文件) -
数值比较
在
[[
中必须使用-gt
这类操作符,使用<
这类符号会被当作字符串比较在
((
中,可以用<
符号[[ 2 < 10 ]] # False (exit status 1) (( 2 < 10 )) # True (exit status 0)
参数扩展
${parameter:-word}
:使用默认值,如果parameter
不存在,就以word
作为其值
更多参考man bash
的Parameter Expansion小节
杂项
$?
:这个变量保存了上一条指令的返回值
赋值=
两边不能有空格,判断=
两边必须要有空格
判断是否传入参数(参数是否存在):直接$1
函数获取返回值$(function name)
全局变量???
管道命令执行顺序
用管道连接的命令是同时执行的
比如ps a | grep bash
的执行结果中,会出现grep
的进程
➜ ~ ps a | grep bash
263 pts/0 Ss 0:00 -bash
811 pts/0 S+ 0:00 grep bash
说明在ps
在执行打印进程信息的时候,grep
也在执行了,也就是说ps
和grep
是同时执行的
只不过grep
执行到需要输入的时候就会停下来(状态S+),等待I/O(ps
的标准输出)
Zsh和Bash的兼容性问题
Zsh并不是完全兼容Bash
如果要完全兼容,使用emulate bash
或文件开头添加#!/usr/bin/bash
(直接指定用bash执行该脚本)
目前遇到的不兼容情况:
- 条件表达式中,判断相等,Bash支持双等号
==
,而Zsh只支持单等号=
- curl命令无法正常运行
Shell中的字符串变量更像是C语言中的宏定义,运行时直接替换到目标位置,如果包含空格就容易引起歧义,因此通常将变量写在双引号内"$a"
。
算数运算在((…))中进行,如((i=i+1))
算术运算
Bash arithmetic is limited to integers.
– Problem with Bash Script array arithmetic for simple sine wave generator