简介:
shell脚本 ,就是一个可执行文件,后缀为.sh,文件中是多条要顺序执行的linux命令。
一, Bash基本功能
1,历史命令调用
保存在~/.bash_history,使用history命令察看
上下箭头调用以前历史命令
!n 重复执行第n条命令
!! 重复执行上一条命令
!字串 重复执行最后一条以该字串开头的命令
2,命令和文件补全
tab键
3,别名,定义在~/.bashrc
alias
4,环境变量
$PATH
5,标准输入输出和文件描述符
键盘,/dev/stdin, 0, 标准输入
显示器,/dev/sdtout, 1, 标准输出
显示器,/dev/sdterr, 2, 标准错误输出
6,输出重定向
标准输出重定向:命令 > 文件,命令 >> 文件
标准错误输出重定向:错误命令 2>文件,错误命令 2>>文件
将正确和错误输出重定向到一个文件:命令 > 文件 2>&1,命令 >> 文件 2>&1
将正确和错误输出重定向到一个文件:命令 &> 文件 ,命令 &>> 文件
将正确和错误输出分别保存:命令>>文件1 2>>文件2
不保存任何输出,丢入黑洞:ls &>/dev/null
7,输入重定向
wc 选项 文件名,统计字符,行数
文件 > wc
8,多命令顺序执行
; 顺序执行
&& 前一条命令必须成功执行,后一条才能执行
|| 前一条命令执行失败,后一条才能执行
9,管道符
|,可通过管道符连接两条命令,将第一条的输出当作第二条的输入
注意,有的命令不支持管道符,如find。可使用xargs命令,如
find /tmp -name CVS | xargs -n20 rm -rf
10,前后台运行
可以通过在命令后,添加符号“;”和“&”来分别以前台和后台的方式来执行。
11,环境变量
/etc/profile
/etc/profile.d/*.sh
~/.bash_profile
~/.bashrc
/etc/bashrc
二,如何写和执行:
1,如何写
vi filename.sh
文件中的linux命令用;号隔开。
2,如何执行
1>直接法:bash filename.sh
2>可执行文件法:
文件开头用 #!/bin/bash 声明使用的linux命令库;
赋予执行权限:chmod a+x filename.sh;
./filename.sh或/tmp/filename.sh
3,如何调试
set -x
三,程序设计
1,注释:#
2,变量
1>声明:可通过declare指定,-指定类型,+取消类型,-i声明为整形,-x声明为环境变量,-p显示变量类型
2>删除:unset
3>声明并赋值:name=value
4>调用:$name或${name}
5>数据类型:默认都为字符串
6>环境变量:$PATH,$HOME,$PWD,$USER,$UID,$SHELL, 察看当前环境变量set
7>预定义变量:$?命令执行后返回的状态,$$当前进程的进程号
8>导出变量:export name
被导出的变量在当前shell脚本执行的任何程序都会继承这个变量。如添加新路径:export PATH="$PATH:/home/user/bin"
9>导入配置文件中的变量:source file 或 .file
3,运算符
1>整数运算:$(()), $[],let,expr
a=4;b=5;
c=$(($a+$b))
c=$[$a+$b]
let c=$a+$b
c=$(expr $a + $b) #运算符两边要空格!,运算符有+,-,*,/,%,&&,||
2>浮点运算:bc
"4*0.56" | bc #运算符有:+加,-减,*乘,/除,^指数,%余数,a(x) 正弦,c(x) 余弦
在运算前,可设置参数,用;号隔开。如设置精度:"scale=2;3/8" | bc
4,字符串操作
1>长度:${#name}
2>相连:${name}${age}
3>引号:单引号',双引号",反引号`的区别
单引号中的字符会被解析为字符串;如:name='Jason'。
反引号中的字符会被解析为命令。
双引号中的$会被解析为变量,如:name="${firstName}.${lastName}";
双引号中的`会被解析为命令,如:name="`whoami`"。
4>字符串转数组
string="a c d"
arr=($string)
5>字符串截取
string="http://www.baidu.com/index.html"
截取左边:string=${string#*//} 得到 "www.baidu.com/index.html"
截取右边:string=${string%/*} 得到 "www.baidu.com"
5,数组
1>定义:array_var=(1 2 3 4 5);
2>使用:${array_var[0]}
3>长度:${#array_var[*]}
4>全部:${array_var[*]}
5>添加:array_var=(${array_var[*]} ${newItem})
6>遍历
for((i=0;i<${#array_var[*]};i++))
do
echo ${array_var[i]};
done
或
for var in ${array_var[*]}
do
echo $var;
done
6,控制语句
1>条件:if,else
if [ $name = 'admin' ]
then
echo 'admin';
fi
if [ $name = 'admin' ]
then
echo 'admin';
else
echo 'user';
fi
if [ $name = 'admin' ]
then
echo 'admin';
elif [ $name = 'dba' ]
echo 'dba';
else
echo 'user';
fi
test 或 [ ] 支持判断数值、字符和文件
(1)数值测试:
-eq:等于
-ne:不等于
-gt:大于
-ge:大于等于
-lt:小于
-le:小于等于
(2)字符串测试:
=:等于
!=:不相等
-z 字符串:字符串长度为零
-n 字符串:字符串长度不为零
(3)文件测试:
-e 文件名:文件存在
-r 文件名:文件存在且可读
-w 文件名:文件存在且可写
-x 文件名:文件存在且可执行
-s 文件名:文件存在且至少有一个字符
-d 文件名:文件存在且为目录
-f 文件名:文件存在且为普通文件
-c 文件名:文件存在且为字符型文件
-b 文件名:文件存在且为块文件
非(”!”)、且(“-a”)、或(“-o")。三个逻辑操作符用于将测试条件连接起来。
注意:[]内侧和符号两边都要空格!!!
2>条件:case
read -p "Please choose yes/no: " -t 30 choose case $choose in "yes") echo "user's choose is yes!" ;; "no") echo "user's choose is no!" ;; *) echo "user's choose is error!" ;; esac
3>循环:for,while,until
固定循环 for:
for i in 1 2 3 4 5 6 7 8 do echo $i done
for((i=0;i<10;i++))
do
echo $i;
done
条件循环 while:
i=0;
while(($i<10))
do
echo $i;
let i++;
done
条件循环 until:
i=0;
until(($i==10))
do
echo $i;
let i++;
done
跳出循环:break,continue
7,函数
1>定义
function fname(){
statement;
}
2>调用
fname arg1 arg2;
3>参数
$1,$2...
参数个数:$#
全部参数字符串:$*
全部参数数组:$@
4>导出函数:export -f fname
4>返回值
return 返回整数
echo 返回字符串(函数中的命令如grep会影响输出,需要重定向)
4>引用
. ./function
四,常用命令
1,输入
从控制台获取输入 read var
1>密码:read -s var
2>提示:read -p "Enter input:" var
3>限制字符数:read -n 2 var
4>限制时间数:read -t 5 var
5>指定定界符:read -d "," var
2,输出
输出到控制台 echo, printf
1> echo:会自动换行。echo -e "\e[1;31m abcd \e[0m" 会将abcd打印为颜色,-e 为支持转义字符
2> printf:格式化输出。
%[-][length]type是格式替换符
type有s,f,替换字符串和浮点数;
length表示显示位数;
默认右对齐,添加-则左对齐:
如:printf "%-10s %-4.2f\n" Smith 90.222
3,字符操作
搜索行:grep
-v 取反
字符流操作:sed
sed [options] 'command' file(s)
options:-i 则修改源文件;-e则多命令操作
command: 由两部分组成:定位+操作
定位:通过指定行号,正则表达式匹配。
操作:添加a;插入i;删除d;行替换c;字符替换s ; 全文正则表达式替换:s/old/new/g , \(re\)保存匹配的字符,用数字1使用;
按列提取:cut
-f 提取第几列
-d 指定分隔符,默认分隔符是tab,不支持空格为分隔符
按行操作:awk
格式:awk '条件1{动作1} 条件2{动作2}...' 文件名
条件一般用关系表达式最为条件,可以没有条件;动作一般为格式化输出或流程控制语句,默认动作是输出。
指定分隔符:-F,如awk -F ':' '{print $1}' /etc/passwd。默认域分隔符是"空白键" 或 "[tab]键"。
常量:FILENAME,文件名;NR,总共解析到第几行;FNR,本文件解析到第几行;NF,本行有几列
awk -F ':' '{print "filename:" FILENAME ",linenumber:" NR ",columns:" NF ",linecontent:"$0}' /etc/passwd
printf:格式化输出
awk -F ':' '{printf("filename:%10s,linenumber:%s,columns:%s,linecontent:%s\n",FILENAME,NR,NF,$0)}' /etc/passwd
搜索动作:/string/
awk -F: '/root/{print $7}' /etc/passwd
编程
起始,结尾做些事
cat /etc/passwd |awk -F ':' 'BEGIN {print "name,shell"} {print $1","$7} END {print "above is name shell pairs"}'
变量
awk 'BEGIN {count=0;print "[start]user count is ", count} {count=count+1;print $0;} END{print "[end]user count is ", count}' /etc/passwd
条件语句
ls -l |awk 'BEGIN {size=0;print "[start]size is ", size} {if($5!=4096){size=size+$5;}} END{print "[end]size is ", size/1024/1024,"M"}'
循环语句和数组
awk -F ':' 'BEGIN {count=0;} {name[count] = $1;count++;}; END{for (i = 0; i < NR; i++) print i, name[i]}' /etc/passwd
排序操作:sort
sort [选项] 文件名
-f:忽略大小写
-n:按数值排序,默认按字符
-r:反向排序
-t:指定分隔符,默认是tab
-k n[,m]:按照指定的列排序,从第n个字段开始,m字段结束,默认到行尾
sort -n -t ":" -k 3,3 /etc/passwd #按照UID排序
统计操作:wc
wc [选项] 文件名
-l:只统计行数
-w:只统计单词数
-m:只统计字符数
4,日期时间
1>查看时间:date
2>格式查看:年,月,日,星期,时,分,秒
date +%Y %b %d %a %H %M %S
3>修改时间:date --date "Jan 20 2014"
4>UTC时间:date +%s
5>延时执行:sleep
5,字符串trim
#trim string
#arg1 = string
function trim(){
echo $1 | sed -e 's/\(^ *\)//' -e 's/\( *$\)//' -e 's/\r//'
}
6,数组contains
#array contains() method
#arg1 = array, arg2 = item
function contains(){
array=($@)
arrayLength=$(( $# - 1 ))
for((k=0;k<${arrayLength};k++))
do
arrayItem=${array[$k]}
if [ $arrayItem = $2 ]
then
echo "true"
return 0
fi
done
echo "false"
}
7,判断命令是否成功
[ $? -eq "0" ];
then
echo "true";
else
echo "false";
fi