用户在命令行输入命令后,一般情况下Shell会fork并exec该命令,但是Shell的内建命令例外,执
行内建命令相当于调用Shell进程中的一个函数,并不创建新的进程。cd、 alias、 umask、 exit等命令即是内建命令,凡是用which命令查不到程序文件所在位置的命令都是内建命令,内建命令没有单独的man手册.
在man手册中查看内建命令
man bash-builtins
本地变量赋值
VARNAME=value #不能有空格,否则会被Shell解释成命令和命令行参数
导出为环境变量
export VARNAME
export VARNAME=value
删除本地/环境变量
unset VARNAME
使用变量 ${}
${VARNAME} #或$VARNAME,不过容易歧义
文件名通配符 ?*[]
通配符 | 意义 |
---|---|
? | 匹配一个任意字符 |
* | 匹配0个或多个任意字符 |
[] | 匹配方括号中任意一个字符的一次出现 |
ls /dev/ttyS*
ls ch0?.doc
ls ch0[0-2].doc
ls ch[012][0-9].doc
命令替换 “ $()
由反引号括起来的也是一条命令, Shell先执行该命令,然后将输出结果立刻代换到当前命令行中。
DATE=`date` #或 DATE=$(date)
echo ${DATE}
算术代换: $(())
$(())中的Shell变量取值将转换成整数,只能用+-*/和()运算符,并且只能做整数运算。
VAR=45
echo $(($VAR+3))
转义字符 \
touch \$\ \$ #创建一个 [$ $]文件
在\后敲回车表示续行, Shell并不会立刻执行命令,而是把光标移到下一行。
单引号/双引号
echo '$SHELL' # $SHELL
echo "$SHELL" # /bin/bash
条件测试: test [
命令test或[可以测试一个条件是否成立,如果测试结果为真,则该命令的Exit Status为0,如果测
试结果为假,则命令的Exit Status为1(注意与C语言的逻辑表示正好相反)。
VAR=2
test $VAR -gt 1
echo $?
0
test $VAR -gt 3
echo $?
1
[ $VAR -gt 3 ]
echo $?
1
条件测试 | 意义 |
---|---|
[ -d DIR ] | 如果DIR存在并且是一个目录则为真 |
[ -f FILE] | 如果FILE存在且是一个普通文件则为真 |
[ -z STRING ] | 如果STRING的长度为零则为真 |
[ -n STRING ] | 如果STRING的长度非零则为真 |
[ STRING1 = STRING2 ] | 如果两个字符串相同则为真 |
[ STRING1 != STRING2 ] | 如果两个字符串不相同则为真 |
[ ARG1 OP ARG2 ] | ARG1和ARG2应该是整数或者取值为整数的变量 OP是-eq(等于) -ne(不等于) -lt(小于) -le(小于等于) -gt(大于) -ge(大于等于)之中的一个 |
逻辑运算 | 意义 |
---|---|
[ ! EXP1 ] | EXPR可以是上表中的任意一种测试条件, !表示逻辑反 |
[ EXP1 -a EXP2] | EXPR1和EXPR2可以是上表中的任意一种测试条件, -a表示逻辑与 |
[ EXP1 -o EXP2 ] | EXPR1和EXPR2可以是上表中的任意一种测试条件, -o表示逻辑或 |
if/then/elif/else/fi
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
if :; then echo "always true"; fi # :是一个特殊的命令,称为空命令,该命令不做任何事,但Exit Status总是真
case/esac
case命令可类比C语言的switch/case语句, esac表示case语句块的结束。 C语言的case只能匹配整
型或字符型常量表达式,而Shell脚本的case可以匹配字符串和Wildcard,每个匹配分支可以有若干
条命令,末尾必须以;;结束,执行时找到第一个匹配的分支并执行相应的命令,然后直接跳
到esac之后,不需要像C语言一样用break跳出。
echo "Is it morning? Please answer yes or no."
read YES_OR_NO
case "$YES_OR_NO" in
yes|y|Yes|YES)
echo "Good Morning!";;
[nN]*)
echo "Good Afternoon!";;
*)
echo "Sorry, $YES_OR_NO not recognized. Enter yes or no."
exit 1;;
esac
exit 0
for/do/done
for FRUIT in apple banana pear; do
echo "I like $FRUIT"
done
#将当前目录下的chap0、 chap1、 chap2等文件名改为chap0~、 chap1~、 chap2~等,末尾有~字符的文件名表示临时文件
for FILENAME in chap?; do mv $FILENAME $FILENAME~; done
for FILENAME in `ls chap?`; do mv $FILENAME $FILENAME~; done
while/do/done
echo "Enter password:"
read TRY
while [ "$TRY" != "secret" ]; do
echo "Sorry, try again"
read TRY
done
COUNTER=1
while [ "$COUNTER" -lt 10 ]; do
echo "Here we go again"
COUNTER=$(($COUNTER+1))
done
位置参数和特殊变量
位置参数和特殊变量 | 意义 |
---|---|
$0 | 相当于C语言main函数的argv[0] |
$1、 $2… | 这些称为位置参数( Positional Parameter) ,相当于C语言main函数的argv[1]、 argv[2]… |
$# | 相当于C语言main函数的argc - 1,注意这里的#后面不表示注释 |
$# | 表示参数列表”$1”,”$2” …,例如可以用在for循环中的in后面。 |
$? | 上一条命令的Exit Status |
$$ | 当前Shell的进程号 |
函数
和C语言类似, Shell中也有函数的概念,但是函数定义中没有返回值也没有参数列表。
foo(){ echo "Function foo is called";}
echo "-=start=-"
foo
echo "-=end=-"
Shell函数没有参数列表并不表示不能传参数,事实上,函数就像是迷你脚本,调用函数时可以传任意个参数,在函数内同样是用$0,$1,$2等变量来提取参数,函数中的位置参数相当于函数的局部
变量,改变这些变量并不会影响函数外面的$0, $1, $2等变量。函数中可以用return命令返回,如
果return后面跟一个数字则表示函数的Exit Status。
is_directory()
{
DIR_NAME=$1
if [ ! -d $DIR_NAME ]; then
return 1
else
return 0
fi
}
for DIR in "$@"; do
if is_directory "$DIR"
then :
else
echo "$DIR doesn't exist. Creating it now..."
mkdir $DIR > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Cannot create directory $DIR"
exit 1
fi
fi
done
Shell脚本的调试方法
-n 读一遍脚本中的命令但不执行,用于检查脚本中的语法错误
-v 一边执行脚本,一边将执行过的脚本命令打印到标准错误输出
-x 提供跟踪执行信息,将执行的每一条命令和结果依次打印出来
sh -x ./script.sh
#! /bin/sh -x
if [ -z "$1" ]; then
set -x
echo "ERROR: Insufficient Args."
exit 1
set +x
fi