您的位置:首页 > 运维架构 > Shell

【APP】Shell脚本简单总结及编写脚本中的小技巧 推荐

2013-05-17 23:35 656 查看
主要从以下几个方面进行bash入门级的总结:

1、命令历史、命令补全
2、管道、重定向
3、命令别名和命令替换
4、命令行编辑
5、文件名通配
6、Bash的相关配置文件及变量
7、编程(条件判断、循环控制)
8、bash中的数组
9、shell编程技巧和编程规范

1、命令历史、命令补全

查看命令历史:history
-c:清空命令历史
-d OFFSET
: 删除指定位置的命令
-w:保存命令历史至历史文件中,这对于经常在不同的终端上执行命令很有用

命令历史的使用技巧:
!n:执行命令历史中的第n条命令;
!-n:执行命令历史中的倒数第n条命令;
!!: 执行上一条命令;
!string:执行命令历史中最近一个以指定字符串开头的命令
!$:引用前一个命令的最后一个参数;
Esc, .
Alt+.

命令补全,路径补全
命令补全:搜索PATH环境变量所指定的每个路径下以我们给出的字符串开头的可执行文件,如果多于一个,两次tab,可以给出列表;否则将直接补全;
路径补全:搜索我们给出的起始路径下的每个文件名,并试图补全;

2、管道、重定向

管道------前一个命令的输出,作为后一个命令的输入
命令1 | 命令2 | 命令3 | ...
如:cat /var/log/message |less
find ./ -name ex* | xargs mv /backup

> 覆盖输出
>> 追加输出
2> 重定向错误输出
2>> 追加方式
&> 重定向标准输出或错误输出至同一个文件
< 输入重定向
<< Here Document
:> file 清空一个文件

对于Here Document举个实例:
cat >> /etc/hosts << EOF
172.28.9.45www01.opsmysql.com
172.28.9.46www02.opsmysql.com
172.28.9.47www03.opsmysql.com
172.28.9.48www04.opsmysql.com
EOF

"*/5 * * * * /usr/sbin/ntpdate ntp.api.bz > /dev/null 2>&1
/dev/null 2>&1 : 意思是将标准输出和错误输出全部重定向到/dev/null中

3、命令别名和命令替换
命令别名
alias CMDALIAS='COMMAND [options] [arguments]'
在shell中定义的别名仅在当前shell生命周期中有效;别名的有效范围仅为当前shell进程;

ualias CMDALIAS

对于我们设定别名的命令,如果要使用没有设定别名时的命令格式,即默认格式可以在命令前面加上: \
\CMD

对于别名我们还可以写在配置文件中:
全局配置文件:/etc/bashrc
用户配置文件:~/.bashrc

命令替换: $(COMMAND), 反引号:`COMMAND`
把命令中某个子命令替换为其执行结果的过程
如:
echo "The date time is : `date`"
echo "The date time is : $(date +%F)"

bash支持的引号:
``: 命令替换
"": 弱引用,可以实现变量替换
'': 强引用,不完成变量替换

4、命令行编辑
光标跳转:
Ctrl+a:跳到命令行首
Ctrl+e:跳到命令行尾
Ctrl+u: 删除光标至命令行首的内容
Ctrl+k: 删除光标至命令行尾的内容
Ctrl+l: 清屏

5、文件名通配:globbing

*: 任意长度的任意字符
?:任意单个字符
[]:匹配指定范围内的任意单个字符
[abc], [a-m], [a-z], [A-Z], [0-9], [a-zA-Z], [0-9a-zA-Z]
[:space:]:空白字符
[:punct:]:标点符号
[:lower:]:小写字母
[:upper:]: 大写字母
[:alpha:]: 大小写字母
[:digit:]: 数字
[:alnum:]: 数字和大小写字母

# man 7 glob
[^]: 匹配指定范围之外的任意单个字符

[[:alpha:]]*[[:space:]]*[^[:alpha:]]

6、Bash相关配置文件及变量

bash的配置文件:
全局配置
/etc/profile, /etc/profile.d/*.sh, /etc/bashrc
个人配置
~/.bash_profile, ~/.bashrc

profile类的文件:
设定环境变量
运行命令或脚本

bashrc类的文件:
设定本地变量
定义命令别名

登录式shell如何读取配置文件?
/etc/profile --> /etc/profile.d/*.sh --> ~/.bash_profile --> ~/.bashrc --> /etc/bashrc

非登录式shell如何配置文件?
~/.bashrc --> /etc/basrc --> /etc/profile.d/*.sh

关于环境变量命令介绍:
1.echo 显示某个环境变量值 echo $PATH
2.export 设置一个新的环境变量 export HELLO="hello" (可以无引号)
3.env 显示所有环境变量
4.set 显示本地定义的shell变量
5.unset 清除环境变量 unset HELLO
6.readonly 设置只读环境变量 readonly HELLO

常见的环境变量
PATH:决定了shell将到哪些目录中寻找命令或程序
HOME:当前用户主目录
MAIL:是指当前用户的邮件存放目录
SHELL:是指当前用户用的是哪种Shell
HISTSIZE:是指保存历史命令记录的条数
LOGNAME:是指当前用户的登录名
HOSTNAME:是指主机的名称,许多应用程序如果要用到主机名的话,通常是从这个环境变量中来取得的
LANG/LANGUGE:是和语言相关的环境变量,使用多种语言的用户可以修改此环境变量
PS1:是基本提示符,对于root用户是#,对于普通用户是$
PS2:是附属提示符,默认是“>”。可以通过修改此环境变量来修改当前的命令符

位置变量:
$1, $2, ...$n

特殊变量:
$?:上一个命令的执行状态返回值,echo $0结果如果为0表示成功,非0表示失败.
$0:获取当前执行的shell脚本的文件名,通常结合basename使用
$*:获取当前shell的所有参数,$1 $2 $3 ,注意与$#的区别
$#:获取当前shell命令行中参数的总个数
$$:获取当前shell的进程号(PID)
$!:执行上一个指令的PID
$@:这个程序的所有参数 "$1" "$2" "$3" "…"

注意:有时候变量名很容易与其他文字混淆,比如我们在某个变量的值后面追加内容:
num=2
echo "this is the $numnd"
这并不会打印出"this is the 2nd",而仅仅打印"this is the ",因为shell会去搜索变量numnd的值,但是这个变量时没有值的。可以使用花括号来告诉shell我们要打印的是num变量:
num=2
echo "this is the ${num}nd"
这将打印: this is the 2nd

变量名不能以数字开头!!!!!!!!!!!!!!!!

+++++++++++++++++++++++++++++++++++++++++++++++++++++
shell中如何进行算术运算:
A=3
B=6
1).let 算术运算表达式
let C=$A+$B
2).$[算术运算表达式]
C=$[$A+$B]
3).$((算术运算表达式))
C=$(($A+$B))
4).expr 算术运算表达式,表达式中各操作数及运算符之间要有空格,而且要使用命令引用
C=`expr $A + $B`

这些计算方法都是shell编程的基础!!!

shell中关于字符串的简单操作:
取字符串长度
A="admin"
echo ${$A} 或 expr length $A

字符串的替换与删除操作:
${变量#关键字}--------->若变量内容从头开始的资料符合‘关键字’,则将符合的最短资料删除
如:echo

${变量##关键字}--------->若变量内容从头开始的资料符合‘关键字’,则将符合的最长资料删除

${变量%关键字}--------->若变量内容从尾向前的资料符合‘关键字’,则将符合的最短资料删

${变量%%关键字}--------->若变量内容从尾向前的资料符合‘关键字’,则将符合的最长资料删除

${变量/旧字串/新字串}--------->若变量内容符合‘旧字串’则‘第一个旧字串会被新字串取代

${变量//旧字串/新字串}--------->若变量内容符合‘旧字串’则‘全部的旧字串会被新字串取代

7、编程(条件判断、循环控制)

下面总结下条件测试类型
整数测试
字符测试
文件测试

条件测试的表达式:
[ expression ]
` expression ` -----在Bash高版本中基本上只能用这个高级的了...上面那个会报错!
test expression

整数比较:
-eq: 测试两个整数是否相等;比如 $A -eq $B
-ne: 测试两个整数是否不等;不等,为真;相等,为假;
-gt: 测试一个数是否大于另一个数;大于,为真;否则,为假;
-lt: 测试一个数是否小于另一个数;小于,为真;否则,为假;
-ge: 大于或等于
-le:小于或等于

间逻辑关系:
逻辑与: &&
第一个条件为假时,第二条件不用再判断,最终结果已经有;
第一个条件为真时,第二条件必须得判断;
逻辑或: ||

注意:[ 条件1 -a 条件2 ] 等价于 [ 条件1 ] && [ 条件2 ]

还有一点要注意:
可以
[[ 条件1 && 条件2 ]]这样使用
不可以
[ 条件1 && 条件2 ]这样使用

字符测试:
==:测试是否相等,相等为真,不等为假
!=: 测试是否不等,不等为真,等为假
\>
\<
-n string: 测试指定字符串是否为空,空则真,不空则假
-z string: 测试指定字符串是否不空,不空为真,空则为假
string ="" 字符串为空
string !="" 字符串不为空

文件测试:
-e FILE:测试文件是否存在
-f FILE: 测试文件是否为普通文件
-d FILE: 测试指定路径是否为目录
-s FILE: 判断文件是否存在且大小大于0
-r FILE: 测试当前用户对指定文件是否有读取权限
-w FILE: 文件是否可写
-x FILE: 文件是否可执行

再简单说下脚本退出状态码

exit: 退出脚本
exit #
如果脚本没有明确定义退出状态码,那么,最后执行的一条命令的退出码即为脚本的退出状态码;
通常:
# 是 0 表示正常退出
# 非 0 表示错误退出

+++++++++++++++++++++++++++++++++++++++++++++++++
条件判断--if
单分支if语句
if 判断条件; then
statement1
statement2
...
fi

双分支的if语句:
if 判断条件; then
statement1
statement2
...
else
statement3
statement4
...
fi

多分支的if语句:
if 判断条件1; then
statement1
...
elif 判断条件2; then
statement2
...
elif 判断条件3; then
statement3
...
else
statement4
...
fi

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
选择结构--case
case SWITCH in
value1)
statement
...
;;
value2)
statement
...
;;
*)
statement
...
;;
esac

说明:value1) 是正则表达式样式,可以用下面字符:
* 任意长度的字符串
C* 表示以C字符开头的字符串
? 任意单个字元,???? 表示4个字符的字符串
[abc] a, b, 或c三字元其中之一,如:[abc]123,匹配a123或b123或c123。
[a-n] 从a到n的任一字元
| 多重选择,分隔符

+++++++++++++++++++++++++++++++++++++++++++++
循环控制---for
两种用法:
for 变量 in 列表; do
循环体
done

for (( expr1 ; expr2 ; expr3 )); do
循环体
done

循环控制---while
while CONDITION; do
statment
done
进入循环:条件满足
退出循环:条件不满足

while的特殊用法一(死循环):
while :; do
statment
done

while的特殊用法二(从某个文件中读取行):
while read LINE; do
statment
done < /PATH/TO/SOMEFILE

方法二另外一种写法:
cat ip.txt | while read line
do
echo $line
done

循环控制---until
until跟while相反,可参照while
until CONDITION; do
statement
...
done

判断条件是否成立,不成立就执行循环体,成立就退出!

循环控制语句
break
中断循环,而后执行循环后面的语句;默认是跳出一层循环,如果要跳出多层循环,可以用 break n(n是大于1的数字,也就次数)。
continue
中断当前这一次循环,提前进入下一次循环,默认跳过一层循环,如果要跳过多层循环,可以用 continue n(n是大于1的数字,也就次数)。

++++++++++++++++++++++++++++++++++++++++++++++++++++++
select (产生菜单选择)
select 表达式是一种bash的扩展应用,尤其擅长于交互式使用,用户可以从一组不同的值中进行选择.
select 命令可以建立简单的列表,结构类似for循环,一般与case语句结合使用。
下面写一个实例:
#!/bin/bash
echo "What is your favourite OS?"
select var in "Linux" "Gnu Hurd" "Free BSD" "Other"; do
break
done
echo "You have selected $var"

8、bash中的数组使用
数组赋值方式:
(1) array=(var1 var2 var3 ... varN)
(2) array=([0]=var1 [1]=var2 [2]=var3 ...
=varN)
(3) array[0]=var1
arrya[1]=var2
...
array
=varN

注意:shell中数组的下标默认是从0开始的!

获取数组元素个数或者长度:
(1) ${#array[@]}
(2) ${#array[*]}

显示数组元素:
echo ${array[*]} #显示所有元素
echo ${array[@]}
echo ${array[@]:0}

echo ${array[0]} #显示第一个元素

echo ${array[@]:2} #不显示数组中前两个元素
echo ${array[@]:0:2} #从第一个元素开始显示两个元素

删除数组中的元素:
unset array[2] #删除第三个元素
unset array #删除整个数组

子串删除:
echo ${array[@]#t*e} # 左边开始最短的匹配:"t*e",这将匹配到"thre"
echo ${array[@]##t*e} # 左边开始最长的匹配,这将匹配到"three"
echo ${array[@] %o} # 从字符串的结尾开始最短的匹配
echo ${array[@] %%o} # 从字符串的结尾开始最长的匹配

子串替换:
echo ${array[@] /o/m} #第一个匹配到的,会被删除
echo ${array[@] //o/m} #所有匹配到的,都会被删除
echo ${array[@] //o/} #没有指定替换子串,则删除匹配到的子符
echo ${array[@] /#o/k} #替换字符串前端子串
echo ${array[@] /%o/k} #替换字符串后端子串

循环列出数组元素:
#!/bin/bash
arr=(ab bc cd)
lenarr=${#arr[@]}
for (( i=0; i<$lenarr}; i++ )); do
echo ${arr[$i]}
done

#!/bin/bash
arr=(ab bc cd)
lenarr=${#arr[@]}
i=0
while [[ $i -lt $lenarr ]]
do
echo ${arr[$i]}
let i++
done

一个实例:
#!/bin/bash
# 设置IFS将分割符 设置为 换行符(\n)
OLDIFS=$IFS
IFS=$'\n'

# 读取文件内容到数组
fileArray=($(cat file.txt))

# restore it
IFS=$OLDIFS
tLen=${#fileArray[@]}

# 循环显示文件内容
for (( i=0; i<${tLen}; i++ )); do
echo "${fileArray[$i]}"
done

9、shell编程技巧和编程规范

检测语法相关:bash -n 脚本名
命令追踪:bash -x 脚本名

shell输入和输出中:
read 用法
cat 特殊用法
echo 特殊用法

后台执行命令:& nohup
如果正在运行一个进程,而且觉得在退出帐户时该进程还不会结束,那么可以使用nohup命令。该命令可以在你退出帐户之后继续运行相应的进程。Nohup就是不挂起的意思( no hang up)。
nohup命令的一般形式为nohup command &
shift 用法
.......
.........
..........
后面略!

简单说下编程规范:

1.文件注释说明
在编写的每个脚本文件中,应当包含文件注释、脚本用途简单描述、版本、作者等...如:

#!/bin/bash
#Description: .......
#Date: xxxx-xx-xx
#Version: ....
#Author: Andy

2.代码注释
3.函数注释--说明该函数的功能

4.变量命名规范化
取名要说明这个变量代表的含义
变量名或函数名不要太长
名称尽量使用大写或大写开头
如:

Passwd
Num_Count

5.代码注意缩进
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  shell bash