第一个shell script程序
#!/bin/bash
# Program:
# this is a test shell script
# 2015/07/10 zhubinqiang Fitst release
echo "Welcome to shell script!"
脚本第一行 指定/bin/bash解释器执行,虽然以#开头 但不是注释
#开头的是单行注释
注释
# 这是单行注释1
# 这是单行注释2
Shell里面没有多行注释,小技巧实现多行注释
COMMENT_BLOCK=
if [ $COMMENT_BLOCK ]; then
===========================
echo "comment1"
echo "comment2"
echo "comment3"
===========================
fi
变量
a=15
version1=$(uname -r)
version2=`uname -r`
echo $a
echo ${version1}
echo $version2
PATH="$PATH:$HOME/bin"
export PATH
unset a
- 变量名=变量, 两边没有空格的。 空格在shell中有特殊用途,分开的话会解释成【命令 参数 参数】的形式
- 变量名区分大小写。 name 与 Name 是两个变量
- 变量有空格的话要用单引号” 或 双引号 “” 将变量内容结合起来
- 上式中$a 与 ${a} 是相同效果的。使用${a} 避免出错
- ‘${a}’ 是强引用 输出${a}。”${a}”是弱引用,输出变量值
- export 使变量成为环境变量
- unset 取消变量
- shell变量是不区分类型的,变量值都是字符串。Bash允许整数比较和运算操作,但变量中只有数字
算术运算
算术运算符
操作符 | 描述 |
---|---|
+ | 加法运算 |
- | 减法运算 |
* | 乘法运算 |
/ | 除法运算 |
% | 求余运算 |
** | 幂运算 |
+= | 加等于 |
-= | 减等于 |
*= | 乘等于 |
/= | 除等于 |
%= | 取模等于 |
let 运算
a=1
let a=a+1
echo $a # 2
let a+=1
echo $a # 3
let "a = a + 2"
echo $a # 5
$((…))运算
a=1
a=$((a+1))
echo $a
expr 运算
a=1
b=`expr $a + 1`
echo $b
if … else … 判断语句
a="hello"
if [ "$a" == "hello" ]; then
echo "Hello, how are you."
elif [ "$a" == "" -o "$a" == '?' ]; then
echo "what?"
elif [ "$a" == 'y' ] || [ "$a" == 'Y' ]; then
echo "Yes"
else
echo "I don't understand you."
fi
[ 左右两边有一个空格, == 左右两边有一个空格,] 左边有一个空格
算术与字符串测试
操作 | 描述 | 操作 | 描述 | |
---|---|---|---|---|
算术比较 | 中括号[…]结构 | 字符串比较 | 中括号[…]结构 | |
-eq | 等于 | =/== | 等于 | |
-ne | 不等于 | != | 不等于 | |
-lt | 小于 | \< | 小于(ASCII) * | |
-le | 小于等于 | |||
-gt | 大于 | \> | 大于(ASCII)* | |
-ge | 大于等于 | |||
-z | 字符串为空 | |||
-n | 字符串不为空 | |||
算术比较 | 双括号((…))结构 | 条件判断 | ||
> | 大于 | -a | 两个条件同时成立 | |
>= | 大小于等于 | -o | 任何一个条件成立 | |
< | 大于 | ! | 非 | |
<= | 小于等于 |
*如果在双中括号[[ … ]]测试中的话,那么不需要转义符\
文件测试
操作 | 描述 | 操作 | 描述 | |
---|---|---|---|---|
-e | 文件是否存在 | -s | 文件大小不为0 | |
-f | 是一个标准文件 | |||
-d | 是一个目录 | -r | 文件具有读的权限 | |
-h | 文件是一个符号链接 | -w | 文件具有写的权限 | |
-L | 文件是一个符号链接 | -x | 文件具有执行权限 | |
-b | 文件是一个块设备 | |||
-c | 文件是一个字符设备 | -g | 设置了sgid标记 | |
-p | 文件是一个管道 | -u | 设置了suid标记 | |
-S | 文件是一个socket | -k | 设置了”粘贴位” | |
-t | 文件与一个终端相关联 | |||
-N | 从这个文件最后一次被读取之后,它被修改过 | F1 -nt F2 | 文件F1比文件F2新 | |
-O | 这个文件的宿主是你 | F1 -nt F2 | 文件F1比文件F2旧 | |
-G | 文件的组id与你所在的组相同 | F1 -nt F2 | 文件F1和F2都是同一个文件的硬链接 | |
! | “非”(翻转上边的测试结果) |
Case
像C语言中的switch… case…
a="hello"
case $a in
"hello")
echo "Hello, how are you." ;;
"")
echo "what?" ;;
*)
echo "I don't understand you." ;;
esac
while 循环
i=0
s=0
while [ "$i" -le 100 ];do
s=$((s+i))
i=$((i+1))
done
echo "1 + 2 + 3 + ... + 100 = $s"
until 循环
i=0
s=0
until [ "$i" -gt 100 ]; do
s=$((s+i))
i=$((i+1))
done
echo "1 + 2 + 3 + ... + 100 = $s"
for 循环
for i in Tom Jack John; do
echo $i
done
for i in $(seq 1 5); do
echo $i
done
for i in {1..5}; do
echo $i
done
for((i=0; i<5; i++)); do
echo $i
done
数组
array=(5 4 3 2 1)
echo ${array[0]} # 第一个元素
len=${#array[*]} # 数组长度
for((i=0; i<$len; i++));do
echo ${array[$i]}
done
for i in ${!array[@]}; do
echo ${array[$i]}
done
函数
函数定义
function function_name {
command...
}
function function_name() {
command...
}
function_name() {
command...
}
使用函数
function sayHello() {
local name=$1
echo "Hello $name"
return 0
}
sayHello "Tom"
return返回的是状态码。 0 表示成功, 非0表示失败。
如果要返回值用echo
function sum(){
local a=$1
local b=$2
local s=$((a+b))
echo $s
}
s=`sum 2 3`
echo $s
用shift 获取参数
function sum(){
local a=$1
shift
local b=$1
local s=$((a+b))
echo $s
}
s=`sum 2 3`
echo $s
I/O操作
终端输入,并赋值
read -p "Your name(within 30s):" -t 30 named
echo $named
输出多行
cat << EOF
comment1
comment2
comment3
EOF
I/O重定向
COMMAND > filename # 重定向stdout到文件filename
COMMAND 1> filename # 重定向stdout到文件filename
COMMAND >> filename # 重定向stdout并追加到文件filename
COMMAND 1>> filename # 重定向stdout并追加到文件filename
COMMAND 2> filename # 重定向stderr到文件filename
COMMAND 2>> filename # 重定向stderr并追加到文件filename
COMMAND &> filename # 将stdout和stderr都重定向到filename
COMMAND &>> filename # 将stdout和stderr都重定向并追加到filename
COMMAND > filename 2>&1 # 将stdout和stderr都重定向到filename
COMMAND >> filename 2>&1 # 将stdout和stderr都重定向并追加到filename
管道操作
COMMAND1 | COMMAND2 | COMMAND3
cat /etc/passwd | grep "root" | awk -F":" '{print $1}'
管道操作是由前面的stdin传递过来的。 stderr不会传过去
特殊Shell变量
变量 | 含义 |
---|---|
$0 | 脚本名字 |
$1 | 位置参数 #1 |
$9 | 位置参数 #9 |
${10} | 位置参数 #10 |
$# | 位置参数的个数 |
“$*” | 所有的位置参数(作为单个字符串) |
“$@” | 位置参数的个数(作为独立的字符串) |
${#*} | 传递到脚本中的命令行参数的个数 |
${#@} | 传递到脚本中的命令行参数的个数 |
$? | 返回值 |
$$ | 脚本的进程IP(PID) |
$- | 传递到脚本中的标志(使用set) |
$_ | 之前命令的最后一个参数 |
$! | 运行在后头的最后一个作业的进程ID(PID) |
“ ∗”要用引号引起来,否则默认为” @”
系统环境变量
变量 | 含义 |
---|---|
$IFS | 保存了用于分割输入参数的分割字符,默认识空格 |
$HOME | 当前用户的根目录路径 |
$PATH | 可执行文件的搜索路径 |
$PS1 | 第一个系统提示符 |
$PS2 | 第二个系统提示符 |
$PWD | 当前工作路径 |
$EDITOR | 系统的默认编辑器名称 |
$BASH | 当前Shell的路径字符串 |
$EUID | “有效”用户ID |
字符串操作
表达式 | 描述 |
---|---|
${#string} | $string的长度 |
${string:position} | 在$string中,从position开始提取字串 |
${string:position:length} | 在$string中,从position开始取长度为length的字串 |
${string#substring} | 从变量$string的开头,删除最短匹配$substring的字串 |
${string##substring} | 从变量$string的开头,删除最长匹配$substring的字串 |
${string%substring} | 从变量$string的结尾,删除最短匹配$substring的字串 |
${string%%substring} | 从变量$string的结尾,删除最长匹配$substring的字串 |
${string/substring/replacement} | 使用$replacement,代替第一个匹配的$substring |
${string//substring/replacement} | 使用$replacement,代替所有匹配的$substring |
${string/#substring/replacement} | 如果$string的前缀匹配$substring,那么就用$replacement来代替匹配的$substring |
${string/%substring/replacement} | 如果$string的后缀匹配$substring,那么就用$replacement来代替匹配的$substring |
expr match “$string” ‘$substring’ | 匹配$string开头的$substring*的长度 |
expr “$string” : ‘$substring’ | 匹配$string开头的$substring*的长度 |
expr index “$string” $substring | 在$sttring中匹配到$substring的第一个字符出现 |
expr substr $string $position $length | 在$string中从位置$position开始提取长度为$length的字串 |
expr match “$string” ‘\{$substring}\’ | 在$string的开头位置提取$substring* |
expr “$string” : ‘\($substring)\’ | 从$string的开头位置提取$substring* |
expr match “$string” ‘.*\($substring)\’ | 从$string的结尾提取$substring* |
expr “$string” : ‘.*\($substring)\’ | 从$string的结尾提取$substring* |
* $substring 是一个正则表达式
结构汇总
操作 | 描述 |
---|---|
中括号 | |
if [ Condition ] | 测试结构 |
if [[ Condition ]] | 扩展的测试结构 |
Array[1]=element1 | 数组初始化 |
[a-z] | 正则表达式的字符范围 |
大括号 | |
${variable} | 参数替换 |
${!variable} | 间接变量引用 |
{ command1; command2; … commandN; } | 代码块 |
{string1, string2, string3} | 大括号扩展 |
小括号 | |
( command1; command2 ) | 子shell中执行的命令组 |
Array=(element1 element2 emement3) | 数组初始化 |
result=$(COMMAND) | 在子shell中执行命令,并将结果赋值给变量 |
>(COMMAND) | 进程替换 |
<(COMMAND) | 进程替换 |
双小括号 | |
(( var = 78 )) | 整型运算 |
var=$(( 20 + 5 )) | 整型运算,并将结果赋值给变量 |
引号 | |
“$variable” | “弱”引用 |
‘string’ | “强”引用 |
后置引用 | |
result=`COMMAND` | 在子shell中运行命令,并将结果赋值给变量 |
globbing
*
: 匹配任意长度的任意字符
a*b 匹配 ab, a123b
?
: 匹配任意单字符
a?b 匹配 a1b, a2b
[]
: 匹配指定范围内的 任意单字符
[abc], [a-z], [0-9]
[^]
: 匹配任意范围外的任意单字符
[^a-z0-9]
字符合集
[[:space:]]
: 所有空白字符
[[:punct:]]
: 所有标点字符
[[:lower:]]
: 小写字母
[[:upper:]]
: 大写字母
[[:alpha:]]
: 所有字母
[[:digit:]]
: 数字
[[:alnum:]]
: 字母数字
举例:在/urs/lib/下列出 以l开头,中间有数字,结尾是小写字母
ls /usr/lib/l*[[:digit:]]*[[:lower:]]
echo -e '\033[32mHello\033[0m'
\033[
\033
: Ctrl
单个数字:控制字体
3#: 3表示控制其前景色, #是一个数字
4#: 4表示控制其背景色, #是一个数字
组合使用,彼此间使用;
分隔
m: 是固定格式
\033[0m
: 控制符到此结束