Shell script 学习总结
1 .脚本里面的命令们:
read命令:
-p “提示信息” #在用户等待read输入时输出的提示信息
-t 秒数 #指定命令等待的时间,超过此时间还未收到用户输入,则终止命令
-n 字符数 # read命令只接收指定的字符数就开始执行,限制用户输入
-s # 隐藏输入的数据,适用于密码等机密信息的输入情况
读文件里的数据:
如: read f1 f2 f3 f4 < haha.txt把文件哈哈里面第一行的数据分别读入f1 f2 f3 ,其中默认分割为空格,可以用IFS修改,如: IFS=':'便会以:来分割.
eval命令 用来读取变量内容并执行它.
如:
his="ls"
eval $his
which寻找命令的所在位置
如: which ls
locate找到包含关键字的文件路径
如: locate abc将找出所有文件名中包含abc的文件的路径.
date时间
date +'时间格式'
如 date +'%d%H%M'
%d日
%m月
%Y年
%H时
%M分
%S秒
如date +'%Y%m%d%H%M%S' 显示年月日时分秒
date +'%Y-%m-%d-%H-%M-%S'中间用-隔开
cat连接文件内容,并显示
如: cat 1.txt 2.txt > 3.txt把1.txt和2.txt连起来放到3.txt
也可以做简单的编辑器,
cat > 1.txt编辑结束后按 ctrl + d
head输出文件的前一部分.
如:
head -10 1.txt输出1.txt的前10行
tail输出后几行
wc计算文件的总字数或行数.
wc -l总行数
wc -c总字符数
wc -w总单词数
ln链接
ln source destination约等于复制一份
ln -s source destination软链接
find在分层目录中寻找文件
如: find / -name '*.txt'从根目录开始寻找扩展名为.txt的文件.
find . -name '*.sh' -exec rm -f {} \;找到当前目录下的所有.sh文件,并执行命令强制删除
其中{}代表找到的文件,;代表exec命令结束 .
tar打包 打包文件
tar cvzf example.tgz文件路径
tar xvzf解包文件 -C解包到的路径
cut对文件每一行抽出某一部分
cut -c3文件名 :抽出每一行第三个字符
cut -c2-10文件名 :抽出每一行第二到第10个字符
cut -c2-文件名 : 抽出每行第二个后的字符
paste对文件以行和行的方式合并
paste文件1文件2: 把文件1和文件2的每一行都合并,并以Tab键分割
paste -d‘#’文件1文件2: 以#分隔
paste -s文件 以Tab分割,自己合并
tr转换或删除字符
tr k K <文件名 把文件里的k都换成大写的K。
tr ‘,’ ‘\n’ < 文件名 把文件里的,都换成换行字符
tr -d k把字符k全删除
三个可以执行多个命令的方法。
;
&&
||
; 执行时,每个都执行,但不保证都成功
&&执行时,顺序执行,只有前一个成功,下面的才执行
||有一个成功就结束。
script记录命令的执行过程
script文件名 把信息存放在文件里
2 .命令行编辑的方法:
一般用emacs编辑模式,可改set -ovi 改成vi模式,改回来先set +o vi关掉vi ,再set-o emacs.改回来.
Ctrl +a到行首
Ctrl +e到行尾
Ctrl +l清屏
ESC + b左移一个单词
ESC + f右移一个
Ctrl + w往前删除一个单词
ESC + d删除之后的一个单词
Ctrl + k删除右侧一整行所有,
Ctrl + u删除之前的所有
Ctrl + y把刚才删除的复制出来粘贴
3 .脚本里的变量:
变量和函数的取消:
unset -v变量名
unset -f函数名
双引号下可以用$取出变量值
单引号下不可以
RANDOM产生随机数 0 ~ 32767产生的是伪随机数
虚拟文件/dev/urandom运行产生的是随机数
可用:
head -1 /dev/urandom | od -N 2 | head -1 | awk '{print $2 * 1}'来得到.
只读变量:
readonly和 declare
readonly变量名=值
命令readonly可以查看全部的只读变量
readonly -f函数名 设定函数不可修改
readonly -a数组变量 只读数组
如:
s[0]=10
s[1]=20
s[3]=30
readonly -a s
此时s便不可再修改
使用declare命令
declare -r变量名
如:
p=1000
declare -r p
Here Document打包文档.
基本语法:
命令<<标记
......
......
......
标记
会把标记之间的内容利用转向输入的方式交给该命令去处理.
也支持变量替换:
如:
a='haha.txt'
b='hehe'
c='heihei'
cat >$haha <<Here
$b
$c
Here
结果为存成haha.txt文件,内容为:
hehe
heihei
有两种输出格式:
1.关闭变量替换功能;
cat <<'Here'
......
......
......
Here
中间是不支持变量替换的.
2.另一种就是支持,有两种写法:
如:
cat <<Here
或
cat <<"Here"
变量:
三个主题:
1.变量扩展: ${变量名称}
2.命令替换: $(命令)
3.算术扩展: $((算术式))
1.变量扩展:
(1)测试存在性及空值
语法1: ${待测变量-默认值}若变量存在,则符合判断,传出变量值.若不存在传出默认值.
如: r=${myname-'basher'}
语法2: ${待测变量:-默认值}若变量不存在或其值为空,传回默认值
如: r=${myname:-'basher'}
语法3: ${待测变量:=默认值}若变量不存在或为空,则给变量设默认值;以后这个变量就有值了.
语法4: ${待测变量:?提示信息}不存在或为空,显示提示信息,并立刻停止执行脚本
如: r=${myname:?'错误!请提供信息!'}
语法5: ${待侧变量:+真值}变量存在且非空,则传回真值,否则,传回空值.
(2)取字符串切片,字符串长度(即:取字符串的一部分)
字符串第一个字符为0,依次递增.
语法1: ${变量:位置起点}从位置处截取到结束.
如:myname="hello world" r=${myname:4}则r为o world
语法2: ${变量:位置起点:长度}从固定位置截取固定长度.
计算字符串长度:
语法: ${#变量名}传回变量值的字符串长度.
也可用外部程序expr:
法1: len=$(expr length "$str")得出字符串str的长度
法2: len=$(expr "$str" : '.*')
(3)对比样式
对比样式(将符合样式的部分字符串删除或取代)
(1)从前开始对比,删最短
${变量#样式}从头开始,对比变量值,删除最短符合
如:
filename=”/usr/sbin/ntpdate”
r=${filename#/*/}
echo $r
将对比样式/*/。 最终r=”sbin/ntdate”
(2)从前开始对比,删最长
${变量##样式}
filename=”/usr/sbin/ntpdate”
r=${filename##/*/}
echo $r
结果是 r=”ntpdate”
(3)从字符串后对比,删最短
${变量%样式}从右开始
filename=”/usr/sbin/ntpdate”
r=${filename%/*}
echo $r
最后r=”/usr/sbin”
(4)从字符串后对比,删最长
fqdn=www.tnc.edu.cn
m=${fqdn%%.*}
echo $m
最后m=”www”
(5)只替换第一个对比符合的字符串。
${变量/样式/替换字符串}
变量中有符合的样式,则替换成替换字符串。
act=”mail:x:8:8:mail:/var/mail/:/bin/sh”
r=${act/:/,}
echo $r
结果r=” mail,x:8:8:mail:/var/mail/:/bin/sh”
(6)全部替换符合字符串
${变量//样式/替换字符串}
act=”mail:x:8:8:mail:/var/mail/:/bin/sh”
r=${act//:/,}
echo $r
结果r=” mail,x,8,8,mail,/var/mail/,/bin/sh”
(7)把对比匹配的字符串删除
只删一个:
${变量/样式/}
act=”mail:x:8:8:mail:/var/mail/:/bin/sh”
r=${act/:/}
echo $r
结果是 r=” mailx:8:8:mail:/var/mail/:/bin/sh”
全部删除:
${变量//样式/}
act=”mail:x:8:8:mail:/var/mail/:/bin/sh”
r=${act//:/}
echo $r
结果是 r=” mailx88mail/var/mail//bin/sh”
(8)要求样式在句首或句尾。
在对比样式时,在样式前加#,则该样式要出现在变量值的开头才符合;
如:
str=”Yes, This is a TITLE.”
r=${str/#T* /}
echo $r
解释: 位置在句首,T字符后面接任意长度字符,最后以空格结尾的字符串。
由于本例子没满足字符串,故返回原值。
取变量名称列表,数组索引列表
${!开头字符串@}或${开头字符串*}
filename=”ntpdate”
dir=”/usr/sbin”
dir_file=”$dir/$filename”
echo ${!di@}
取得di开头的变量名 结果显示为 dir dir_file
取得数组索引列表
${!数组变量[@]}或 ${!数组变量[*]}
2.命令替换
命令替换即把命令执行后的标准输出放入变量。
语法有以下两种:
1.变量名=$(命令)
2.变量名=·命令·注意不是单引号
Bash会把执行命令后产生的标准输出赋值给指定的变量。会默认删除换行符和\t。
赋值给指定的变量。会默认删除换行符和\t,并转化为空格符.
IFS的内容原为 空格符, \t和\n
如果把IFS改为 IFS=' ' 那么就不会换掉换行符和\t也即是按原样输出.
如果有两个或两个以上的命令在()里:
a=$(cd ..; pwd)两个命令 cd ..和pwd中间用;隔开.则替换的值是最后一个命令的结果.
3.算术扩展
i=$((8+16))
echo $i
结果是24
算术运算
几种方式:
1.算术扩展 $((算术式)) r=$((2+5*8))
2.使用外部程序expr r=`expr 4+5`
3.使用$[ ] r=$[4+5]
4.使用内置命令 declare declare -i r=8+18
5.使用内置命令let let r=8+16
简介:
1. echo $((${j:-8}+2))如果变量j不存在或为空 则为8+2的值
2. 如果变量不存在或为空 则该变量值为0如: echo $((k+4)),如果k不存在或空,则为4
3. 数字以0开头,视为八进制.
4. 以0x开头,为16进制
(1)算术扩展的一些注意事项:
1.如果表达式里有变量,最好不要用$ , 可以直接echo$((12+a))就可以,
2.除法运算(/)时,有余数会无条件舍去,乘方 2**5表示2的5次方.
(2)expr的注意事项:
1.由于它是外部程序,可以更好的跨品台,可移植性高.
2.特殊字符要用\予以转义.并且运算符和操作数之间至少要有一个以上的空格符隔开.
如:
r=`expr 3 \| 0`结果为3
r=`expr 3 \& 0`结果为0
比较: r=`expr 1 \< 2`结果为1
r=`expr 3 \<= 2`结果为0
加: r=`expr 5+4`不用有转义字符和空格,因为+不是特殊字符!!!
乘: r=`expr 5 \* 4`要用
3.对比样式:
示例说明: r=`expr "string" : st`由字符串string开头,对比样式st符合的个数,此例r=2
或写为r=`exprmatch "string" st`
4.找出子字符串的位置,从1开始算
r=`expr index "string" in`查in在字符串"string"中出现的位置 此例r=4
5.取子字符串
r=`expr substr "string" 2 3`由第2个字符开始,取出3个字符长度 此时r='tri'
6.计算字符串长度
r=`expr length "string"` r=6
(3)使用$[ ]注意事项:
1.与$(())类似. r=$[4+5]
(4)使用declare或let注意事项:
1.declare提前改变变量的属性.就可以进行算术运算.
declare -i a声明a为整数,不是字符串
a=8+16
echo $a
2.let与declare相似:
let a=8+16
i=10; j=20;
let i++
let j++
都是可以的.
流程控制
grep -q "abc" abc.txt搜索abc.txt文件里是否有字符串"abc", -q表示不显示,仅借助$?来传回执行结果.
if判断语句:
((0))
((20<30))
((0&&1))
((2&5))
如:
if ((20<30)); then
......
fi
使用内置命令test,来判断真假值,传回0为真,非零为假
&&经常拿来当一种隐形的if语法;
如: [ -z "$PS!" ] && return若$PS为空 则执行return.否则,不执行.
凡是[判断式]&&指令 形式,都视为一种隐形的if-then语法
||也有隐形if的语法.
&& ||合用:有if-then-else的效果
如: [ -n ${DEBUG:-} ] && set -v || set +v
效果是 先判断DEBUG是否存在 存在执行 set -v 不存在执行 set +v
bash中真假以命令的结束状态是否为0来做判断,传回0为真,非零为假.
for循环:
for变量 in串行
do
.....
done
将串行的元素一一取出,依次放在指定的变量中,然后重复执行,直到元素取完.
其中,串行是一些字符串的组合,彼此用$IFS所定义的分割字符(如空格符)隔开,这些字符串称为字段.
for循环经常用在分割字符串行,取出字符元素值.
如:
IFS=':'
PL="root:x:0:0:root:/root:/bin/bash"
for f in $PL
do
echo $f
done
while循环,经典用法是搭配转向输入,读取文件的内容.
while read line
do
echo $line
done < cvsfile
读取输入数据,放入变量line如果读到数据非空,进入循环.
然后将cvsfile的内容转向输入,交给read读取.也就是read实际上读的是cvsfile文件的内容.
如:
IFS=':'
while read f1 f2 f3 f4 f5 f6 f7
do
echo "帐号: $f1, login shell 是: $f7"
done < "/etc/passwd"
把/etc/passwd的各行帐号数据读入f1~f7然后显示.
函数:
格式有三个
function函数名()
{
函数体
}
函数名()
{
函数体
}
function函数名
{
函数体
}
参数可以在函数名后写入:
函数名 参数1参数2参数3 ...
取消函数的定义:
unset -f函数名
如: unset -f function1取消函数1
函数中变量的作用域:
默认是整个脚本文件,可以通过 local a=0 设置a为函数内局部变量,
参数传递:
$0,$1等为参数 $#参数个数 $@所有以空白符隔开的参数 $*所有参数所组成的字符串.
移动位置参数:
shift n n代表要移动的次数,不写代表1.
会把$2移动到$1 , $3移动到$2依次类推,,最后会把所有参数清空.
如:
echo "\$@的初值: $@"
while shift
do
[ -n "$1" ] && echo "shift 1次,\$@的变化: $@"
done