解释性语言语言:python/shell/ruby等脚本语言
编译性语言:C/C++
作为一种Shell编程习惯
应该总是把变量取值放在双引号之中,如[ “$VAR” = ‘abc’ ]
常识
1.脚本文件以 #! 开头,用于指定命令解释器
2.如何执行脚本?
(1)给脚本添加可执行权限:chmod a+x example.sh
(2)执行方式:
./example.sh
. example.sh
source example.sh
/bin/sh example.sh
/bin/bash example.sh
内建命令 (不需要解释器就能执行的命令)
用户在命令行输入命令后,一般情况下Shell会fork并exec该命令,但是Shell的内建命令例外,执行内建命令相当于调用Shell进程中的一个函数,并不创建新的进程。
- 以前学过cd/alias/umask/exit等都是内建命令
- 凡是用which命令[查不到]程序文件所在位置的命令都是内建命令
- 内建命令没有单独的man手册,查看内建命令应该执行man bash-builtins
- 内建命令虽然不创建新的进程,但是也有Exit Status,通常用0表示成功/非零表示失败,Exit Status可以用特殊变量$?读出
小括弧()的特殊用法
区别&&原因
加() | 不加() | |
---|---|---|
区别 | PWD不改变 | PWD改变 |
类比于 | 直接执行./test.sh, PWD不变 | source ./test.sh, PWD改变 |
原因 | 会fork一个子Shell执行小括弧中的命令 | 直接在交互式Shell下执行,改变交互式Shell的PWD |
变量
1.本地变量
2.环境变量
echo $PATH
env|grep $PATH
(1)创建 / 查看环境变量
1.创建本地变量:VAR=hello
2.使用export关键字,将本地变量导出编程环境变量:export VAR
3.查看将VAR定义成环境变量:env | grep VAR
补充:grep
grep VAR # 查询结果是VAR字符串本身
grep $VAR # 查看结果是VAR变量的真实值,即hello
(2)删除变量unset
unset 变量名 # 将已经定义的环境变量/本地变量删除
命令代换
显示命令本来的作用
实现方法由两种
- 命令由 `反引号 (英文输入法模式下,Esc下面的按键)括起来
- 命令由 $() 括起来
算术运算 + - * /
echo $(($VAR+30))
echo $((VAR+30))
echo $[$VAR+30]
echo $[VAR+30] # 最常用
echo $[2#10+30] # 2进制的10 + 10进制的30
echo $[7#11+5#30] # 7进制的11 + 5进制的30
转义字符 \
创建文件$和$test
touch \$ \$test
创建文件-----abc
touch ./-----abc
单双引号
单引号 | 双引号 | |
---|---|---|
单纯打印字符串,没有区别 | ||
防止通配符扩展 | ||
不允许变量扩展 | 允许变量扩展 (打印变量的值) |
条件测试: test 或 [ ]
命令 test 或 [ ] 可以测试一个条件是否成立:如果测试结果为真,则该命令的Exit Status为0;如果测试结果为假,则命令的Exit Status为1(注意与C语言的逻辑表示正好相反)。
语法 | 含义 |
---|---|
[ -d DIR ] | 如果DIR存在并且是一个目录,返回真 |
[ -f FILE ] | 如果FILE存在并且是一个普通文件,返回真 |
[ -z STRING ] | -zero,如果STRING的长度为0,返回真;STRING建议加“ ” |
[ -n STRING ] | -not zero,如果STRING的长度为非0,返回真;STRING建议加“ ” |
[ STRING1 = STRING2 ] | 如果STRING1与STRING2相等,返回真 |
[ STRING1 != STRING2 ] | 如果STRING1与STRING2不相等,返回真 |
[ ARG1 OP ARG2 ] | ARG1和ARG2应该是整数 或 取值为整数的变量,OP是-eq(等于) -ne(不等于) -lt(小于) -le(小于等于) -gt(大于) -ge(大于等于)之中的一个 |
语法 | [ 与 / 或 / 非 ]逻辑运算 |
---|---|
[ ! EXPR] | EXPR可以是上表中的任意一种测试条件,!表示“逻辑非” |
[ EXPR1 -a EXPR2 ] | EXPR1和EXPR2可以是上表中的任意一种测试条件,-a表示“逻辑与” |
[ EXPR1 -o EXPR2 ] | EXPR1和EXPR2可以是上表中的任意一种测试条件,-o表示“逻辑或” |
分支
(1) if/then/elif/then/else/fi
注解:最后一句 if :;then …中的冒号:,该冒号:表示的含义是true
注解:read YES_OR_NO,表示从键盘中读取值,存放在变量YES_OR_NO中,其中read相当于C语言中的gets
(2) case/esac
Shell脚本的case |
---|
不存在switch,只有case…esac |
可以匹配字符串和Wildcard |
每个匹配分支可以有若干条命令,末尾必须以;;结束 |
循环
(1) for/do/done
Shell脚本中的for循环结构,类似于foreach循环,是循环遍历,例如:
- 将ls命令执行结果,一次给变量filename;然后做do…done中间夹的操作
- 将chap?更名为chap?~
(2) while/do/done
尝试输入密码3次
break和continue
break | continue |
---|---|
break[n]可以指定跳出几层循环,用法不同C语言 | continue跳过本次循环,用法同C语言 |
不常用 | 常用 |
位置参数和特殊变量
符号 | 含义 |
---|---|
$? | 上一条命令的Exit Status |
$$ | 当前进程号 |
$0 | 相当于C语言main函数的argv[0] |
$1 $2 … | 相当于C语言main函数的argv[1] argv[2] … |
$# | 相当于C语言函数的argc-1,表示参数的数量,注意这里的#不表示注释 |
$@ | 表示参数列表"$1" “$2” …,例如可以在for循环中的in后面 |
$* | 表示参数列表"$1" “$2” …,例如可以在for循环中的in后面 |
补充:shift
位置参数可以用shift命令左移。比如shift 3表示原来的$1,$2,$3丢弃;$4变成$1,$5变成$2,$6变成$3,以此类推。
Shell中的函数
- 一次性创建多个目录,各目录名通过命令行参数传入,如./create_dir dir1 dir2 dir3 dir4 表示创建目录dir1 dir2 dir3 dir4。
- 脚本逐个测试各个目录是否存在
- 如果不存在,则创建
- 如果存在,则什么也不干
#! /bin/sh
is_directory() # 判断目录$1是否存在,函数返回值是1或0
{
DIR_NAME=$1
if [ ! -d $DIR_NAME ];then
return 1;
else
return 0;
fi
}
for DIR in "$@";do
if is_directory "$DIR";then # 调用函数is_directory判断DIR存在
:
else
echo "$DIR doesn't exist,Creating it now ... "
mkdir "$DIR"
if [ $? == 0 ];then
:
else
echo -e "create dir error\n"
exit 1
fi
fi
done
Shell脚本调试
选项 | 含义 |
---|---|
-n | 读一遍脚本中的命令,但是不执行,用于检查脚本中的语法错误 |
-v | 一边执行脚本,一边将执行过的脚本命令打印到标准错误输出 |
-x | 提供跟踪执行信息,将执行的每一条命令和结果依次打印出来 |
三种常见的使用方法
-
在命令行提供参数,如:
-
在脚本开头提供参数,如:
-
在脚本中使用set x命令启用/禁用参数,可以选定区域进行调试
看下面的例子的执行情况,很显然:
(1) 夹在set -x和set +x中间的语句 ⇒ 既会显示原句,又能显示结果
(2) 不夹在set -x和set +x中间的语句 ⇒ 不显示原句,只显示结果