变量
命名
由数字、字母、下划线组成
只能由字母、下划线开头
赋值
var="abc" 等号两边不能有空格
取值
$parameter
参数展开
${parameter} 如果参数后紧跟其他字符,大括号展开可以避免把参数当做其他参数
${parameter:-word} 如果变量存在且非null,则返回其值;否则返回word 如果变量未定义,则返回默认值
${parameter:=word} 如果变量存在且非null,则返回其值;否则设置为word并返回 如果变量未定义,则设置变量为默认值
${parameter:?message} 如果变量存在且非null,则返回其值;否则显示parameter:message并退出 用来捕捉由于变量未定义而导致的错误
${parameter:+word} 如果变量存在且非null,则返回word;否则返回null 测试变量是否存在
${parameter-word} 如果变量存在,则返回其值;否则返回word 如果变量未定义,则返回默认值
${parameter=word} 如果变量存在,则返回其值;否则设置为word并返回 如果变量未定义,则设置变量为默认值
${parameter?message} 如果变量存在,则返回其值;否则显示parameter:message并退出 用来捕捉由于变量未定义而导致的错误
${parameter+word} 如果变量存在,则返回word;否则返回null 测试变量是否存在。
${parameter#pattern} 如果模式匹配于开头处,则删除匹配的最短部分,并返回剩下的部分
${parameter##pattern} 如果模式匹配于开头处,则删除匹配的最长部分,并返回剩下的部分
${parameter%pattern} 如果模式匹配于结尾处,则删除匹配的最短部分,并返回剩下的部分
${parameter%%pattern} 如果模式匹配于结尾处,则删除匹配的最长部分,并返回剩下的部分
${#parameter} 返回变量值的字符长度
位置参数
$0 Shell程序的名称
$1-9 脚本参数,大于9时,用大括号括起来 ${10}
$# 脚本参数总个数
$*,$@ 一次表示所有命令行参数
"$*" 将所有命令行参数视为单个字符
"$@" 将所有命令行参数视为单独的个体
特殊变量
- 在引用时给予Shell的选项
# 目前进程的参数个数
@ 当前进程的命令行参数。置于双引号内,会把所有参数展开为一个个单独的字符串
* 当前进程的命令行参数。置于双引号内,会把所有参数展开为一个字符串
? 上一个命令的退出状态
$ Shell进程的进程ID
! 最近一个后台命令的进程ID。以此方式存储进程ID,可通过wait命令以供稍后使用
ENV 一旦引用,则仅用于交互式Shell中;$ENV的值是可展开的参数。结果应为要读取和在启动时要执行的一个文件的完整路径名称。这是一个XSI必需的变量
HOME 用户根目录
PATH 命令的查找目录
PWD 当前工作目录
IFS 内部的字段分隔器。例如,作为单词分隔器的字符列表。一般设为空格、制表符、以及换行
LANG 当前locale的默认名称;其他的LC_*变量会覆盖其值
LC_ALL 当前locale的名称;会覆盖LANG与其他LC_*变量
LC_COLLATE 用来排序字符的当前locale名称
LC_CTYPE 在模式匹配期间,用来确定字符类别的当前locale的名称
LC_MESSAGES 输出信息的当前语言的名称
LINENO 行号
NLSPATH 在$LC_MESSAGES(XSI)所给定的信息语言里,信息目录的位置
PPID 父进程的进程ID
PS1 主要的命令提示字符串。默认为"$"
PS2 行继续的提示字符串。默认为">"
PS4 以set -x设置的执行跟踪的提示字符串。默认为"+"
算数展开
$((expression))
括号内除了双引号,其他字符无需转义
退出状态
0 成功
1-125 由命令自己定义
126 命令找到了,但文件无法执行
127 命令找不到
>128 命令因收到信号而死亡
返回值为0-255,大于255的返回值都将被替换为该值除以256的余数
Shell命令
command
Shell命令的寻找顺序:
1. 特殊的内建命令
. : break continue eval exec exit export readonly return set shift times trap unset
1. 特殊内建命令语法上的错误,会导致Shell执行时退出;但一般内建命令语法的错误,不会导致Shell退出
如果特殊内建命令遇到语法错误时不退出shell,则它的退出值应该非零???
2. 以特殊内建命令所标明的变量指定,在命令完成后仍会有影响;一般内建命令或其他命令则不会
2. shell函数
3. 一般的内建命令
alias bg cd command false fc fg getopts jobs kill newgrp pwd read true umask unalias wait
4. 外部命令
Pipeline
[!] command1 [ | command2 ...]
List compound-list
Asynchronous Lists
command1 & [command2 & ... ]
异步执行
Sequential Lists
command1 [; command2] ...
顺序执行
AND Lists
command1 [ && command2] ...
前面的命令执行成功才执行后面的命令
OR Lists
command1 [ || command2] ...
前面的执行失败才执行后面的命令
AND-OR list
一个或多个pipelines,用"&&"和"||"分隔
list
一个或多个AND-OR lists,用";"和"&"分隔,以";"、"&"或""结束
compound-list
一个或多个lists,前后可以跟多个
&&与||优先级相同,具有左结合性
false && echo foo || echo bar = ( false && echo foo ) || echo bar
true || echo foo && echo bar = ( true || echo foo ) && echo bar
Compound command
Grouping Commands
subShell
(compound-list)
在子shell中执行,不改变主shell的环境。一般在新进程中执行,但也许不是
代码块
{ compound-list;}
在当前进程中执行,会改变当前shell的环境
}前必须有分号或换行符
for
for name [ in [word ... ]]
do
compound-list
done
如果省略in word,则默认为in "$@"
case
case word in
[(]pattern1) compound-list;;
[[(]pattern[ | pattern] ... ) compound-list;;] ...
[[(]pattern[ | pattern] ... ) compound-list]
esac
最后一个compound-list,可以不加;;
if
if compound-list
then
compound-list
[elif compound-list
then
compound-list] ...
[else
compound-list]
fi
while
while compound-list-1
do
compound-list-2
done
until
until compound-list-1
do
compound-list-2
done
函数
fname() compound-command[io-redirect ...]
$1,$2...$#,$*,$@都变成函数的位置参数,函数运行完毕后,原来的位置参数会被恢复
$0依旧是脚本名称
重定向
运算符
set -C 打开noclobber选项,如果文件存在,则用>重定向输出时会失败,不会覆盖文件
[n]word 输出重定向,如果文件存在,则覆盖文件
[n]>|word 有移植性问题,避免使用。使noclobber选项失效
[n]>>word 输出重定向,如果文件存在,则追加到文件末尾
<< here document
<<- here document,将所有开头的制表符删除(空格不删除)
[n]<>word 有移植性问题,避免使用。打开一个文件作为输入输出
文件描述符处理
[n]<&word 将输入重定向到文件描述符word
[n]>&word 将输出重定向到文件描述符word
shell脚本是否可以打开超过10个文件,由各shell自行决定,编程时需注意
波浪号展开与通配符
##波浪号展开##
~/xxx 将~展开为$HOME
~$user/xxx 将~$user展开为用户XXX的根目录
##通配符展开##
? 任何单一字符
* 任何字符串或字符
[set] 任何在set里的字符
[!set] 任何不在set里的字符
通配符展开时,会忽略开头为.的文件,如果需要展开此类文件,需要在模式中明确提供.
命令替换
用命令的返回结果替换命令
$(command)
`command`
引用
\ 字符的字面意思
'' 将单引号之间的所有字符都当做字面意思
不可以在单引号引用的字符串里在内嵌一个单引号
"" 双引号内的转义、变量、算数、命令替换都会被处理
单引号在双引号里没有特殊意义
在双引号中,$、"、'、\这些符号,如果需要引用其字面意思,前面必须加上\
执行顺序
1. 将命令分割成tokens
2. 检查第一个token,开放的关键字/其他关键字/非关键字
3. 检查第一个token,别名/非别名
4. 波浪号展开
5. 变量展开
6. 命令替换
7. 算数展开
8. 对展开的文本进行单词分割
9. 通配符展开
10.命令查找:特殊内建命令->函数->一般内建命令->可执行文件
执行命令
内建命令
.
读取文件并于当前的Shell中执行文件中的内容
. file
如果file中不带/,则在$PATH中查找
file不要求可执行,可读即可
:
不做任何事,只做参数的展开
: [argument ...]
alias
隐藏或显示别名
alias [alias-name[=string] ...]
展开别名时不会递归展开
bg
break
break [n] 中断多少个被包含的循环
cd
改变工作目录
cd [−L | −P] [directory]
cd - 回到上一次的目录
command
在查找要执行的命令时,避开shell中的同名函数
command [−p] command_name [argument ...]
在函数中如果要执行同名的命令,可以用command xxx
-p 查找命令时,使用$PATH的默认值,而非当前的设置,确保能找到系统的工具
continue
continue [n] 继续多少个被包含的循环
eval
取出eval的参数,并再执行它一次
eval [argument ...]
var="ls | more"
$var ==> ls: more: No such file or directory ls: |: No such file or directory
shell在执行时,把|和more当成了ls的参数。因为在步骤1时,shell解析管道字符|。而执行$var时,管道字符已经解析完毕,所以shell只把$var当做普通的变量展开
eval $var
将var的内容重新让shell解析并执行,执行正确
exec
重新执行一个程序,或改变I/O设置
exec [command [argument ...]]
exec 3< xxx 用文件描述符3读取xxx
exec 4> xxx 将文件描述符4输出至xxx
exec 5<&0 复制文件描述符0到文件描述符5
exec 3<&− 关闭文件描述符3
exec cat maggie 执行命令或程序时,exec为单项操作,控制权不可能再回到脚本,除非无法调用命令或程序
exit
使Shell返回一个退出值
exit [n]
如果没有参数,则以最后一个执行命令的退出状态作为默认的退出状态
export
输出或设置环境变量
export −p 输出环境变量(value有引号)
export name[=word]... 将name设为环境变量
false
什么都不做,返回一个false
fc
fg
getopts
getopts optstring name [arg...]
optstring 合法的选项字母字符串,如果字母后有:,则表示该选项需要一个参数
name 变量名称,每次调用getopts时,把当前处理的选项名称放到name中
OPTARG 如果选项有参数,放置到OPTARG中
OPTIND 下一个要处理的参数索引,一般调用完getopts后,通过shift $((OPTARG - 1))来删除所有处理过的参数
jobs
kill
newgrp
pwd
返回当前的目录
pwd[−L| −P]
read
从标准输入读取数据,并分配给变量
read [−r] var...
-r 读取原始数据,不做任何处理,不将结尾处的反斜杠解释为续行符
如果读取的信息多于变量,剩下所有的信息赋给最后一个变量
一旦遇到EOF,返回失败
IFS 决定read对输入的分隔符
readonly
输出或设置环境变量
readonly −p 输出环境变量(value有引号)
readonly name[=word]... 将name设为环境变量
return
从函数中返回值
return [n]
set
显示所有Shell变量的名称与值;改变位置参数;打开或停用Shell选项
set 显示所有Shell变量的名称与值
set c a c Set $1, $2, and $3 and set "$#" to 3
set −− Unset all positional parameters
set −− "$x" Set $1 to the value of x , even if it begins with ’−’ or ’+’
set −− $x Set the positional parameters to the expansion of x , even if x expands with a leading ’−’ or ’+’
set -o 显示当前设置
set +o 显示当前设置,输出与-o有区别
set ±var 打开/停用shell选项
-a allexport 输出所有后续被定义的变量
-b notify 立即显示工作完成的信息,而不是等待下一个提示号。供交互使用
-C noclobber 不允许>重定向到以存在的文件。>|可以使此选项失效。攻交互使用
-e errexit 当命令以非0状态退出时,则退出Shell
-f noglob 停用通配符展开
-h 当函数被定义(而非函数被执行)时,寻找并记住从函数体中被调用的命令位置(XSI)
-m monitor 打开工作控制。供交互使用
-n noexec 读取命令且检查语法错误,但不要执行。交互式Shell被允许忽略此选项
-u nounset 视未定义的变量为错误,而非null
-v verbose 在执行命令前打印命令(逐字打印)
-x xtrace 在执行前先显示命令(展开后)
ignoreeof 不允许以Ctrl-D退出Shell
nolog 关闭函数定义的命令历史记录
vi 使用vi风格的命令行编辑。供交互使用
shift
shift 一次将命令行参数向左移一位
shift digit 一次将命令行参数向左移digit位
times
打印运行时间
%dm%fs %dm%fs , , ,
%dm%fs %dm%fs , , ,
trap
true
什么都不做,返回一个true
umask
unalias
删除别名的定义
unalias alias-name...
unalias −a
unset
unset -v: 删除变量
unset -f: 删除函数
wait
其他命令
env
env: 输出环境变量(value没有引号)
-i: 初始化环境变量,启动命令
-u: 删除环境变量
test
test [expression]
[ [expression] ]
-e file file存在
-s file file不为空
-f file file是一般文件
-d file file是目录
-b file file是块设备文件
-c file file是字符设备文件
-p file file是命名管道(FIFO)
-S file file是socket
-h file file是符号链接
-L file file是符号链接,同-h
-r file file是可读的
-w file file是可写入的
-x file file是可执行的,或file是可被查找的目录
-g file file有设置setgid位
-u file file有设置setuid位
string string不是null
-n string string非null
-z string string是null
s1 = s2 字符串s1等于s2
s1 != s2 字符串s1不等于s2
n1 -eq n2 整数n1等于n2
n1 -ne n2 整数n1不等于n2
n1 -lt n2 整数n1小于n2
n1 -gt n2 整数n1大于于n2
n1 -le n2 整数n1小于等于n2
n1 -ge n2 整数n1大于等于n2
-t n 文件描述符n指向以终端
如果有多重条件,建议用shell级别的测试,而非-a -o
if[ -f "abc" ] && [ -d "123" ]
所有的shell变量展开都应该用引号括起来
if[ -f "$var" ] 正确
if[ -f $var ] 错误,如果$var为空,则test接收的参数小于所需要的,后续行为无法预料
字符串比较时,在前面置一个其他字母
if[ "X$var1" = "X$var2" ] 如果字符串为空,或者字符串开头带减号,则test命令容易混淆
只能进行整数测试
printf
printf format[argument...]
如果希望文字靠左显示,加-
basename