linux shell编程
preparing
查看当前操作系统的默认shell echo $SHELL
vimrc的推荐配置(非必须)
set nu set cursorline set autoindent autocmd BufNewFile *.sh 0r ~/.vim/template/sh —>创建新文件的头文件
cd ..;ls #进入上一级目录再执行ls,结束后wd位于..
(cd ..;ls) #进入上一级目录再执行ls,结束后wd位于.(fork,exec)
#内建命令&外部命令(通过环境变量)
#查看环境变量
env $path
说明:在学习时,以下提到的命令和demo大多可直接在shell中运行,无需编写成shell文件
第一个shell文件(vim sample.sh)
#!/bin/bash #指定解析器
#仅支持单行注释,多行可以通过语句块实现
date
echo ""
echo "we are current in following path"
/bin/pwd
shell的运行(三种)
chmod +x sample.sh ./sample.sh
. sample.sh
bash sample.sh
数据类型和变量
shell中只有字符串类型,有两种变量类型: 环境变量(类似于全局变量) 本地变量(类似于局部变量)
#声明变量
var=10 #不能有空格
#查看变量的值
echo $var #或 echo ${var} [推荐]
#删除变量
unset var
#控制语句
if,else,switch case,for,while...
#函数
匹配&代换
匹配
* 匹配0或任意个字符
? 匹配一个任意字符
[若干字符] 匹配方括号中的任意一个字符的一次出现 ([a-z])
命令代换
now=$(date) #将date命令运行的结果赋值给now变量等价于以下命令:
now=`date`
算术代换
使用$(())用于算术运算,(())中的变量取值将转换到整数,功能同 $[]
var=10
echo $(($var+5)) #15 == echo $[$var+5] == echo $[$var+5] == echo $((${var}+5))
#注:只能进行+1*/和()运算且只能进行整数运算。
#进制
echo $[2#11+3] #二进制的"11" + 3
转义字符
shell使用 “\” 作为转义字符,用于去除紧跟其后的一个字符的特殊含义,即紧跟其后的字符取字面值[转特殊义或转本身义,参考echo参数节]
echo \$path #-----> $path
#创建 名为 --abc 的文件
touch -- --abc
单双引号
单双引号内的内容都将被视为单一字符串,区别在于 双引号阻止通配符的扩展但允许变量扩展
var=hello
echo "$var" #==> hello
echo '$var' #==> $var
条件测试
条件测试结果 —> 真:0 假:1 (类似于unix的syscall)
算术比较符(greater,less than…):
arg1 op arg2 (只能为整数)
-gt 大于 -ge 大于等于 -eq 等于
-lt 小于 -le 小于等于 -ne 不等于
var=10
test $var -gt 11 #===>等价于 [ $var -gt 11 ] 空格不能少(相当于[是运算符)
echo $? #查看上一次命令运行的结果
文件类型比较符
-d arg 存在且是一个目录为真 -f arg 存在且是一个文件为真 -p arg 存在且是一个管道为真 -l arg软连接 -c arg 字符设备 -b arg 块设备 -s socket文件
# 当前目录下存在一个名为 go 的文件夹
[ -d go ] #===>echo $? --->0
mkfifo ww
[ -p ww ] #===>echo $? --->1
逻辑运算
-a 逻辑与 -o 逻辑或 ! 逻辑非
expr1 -a expr2
! expr
字符串比较符
-z 如果字符串的长度且为0则为真,-n 如果字符串长度不为0为真
判断字符串相等/不等 == ,!=
#变量不存在时(!!!注意变量前的$不能少):
unset var
[ -z $var ] #===>echo $? --->0
[ -n $var ] #===>echo $? --->0
var="abc"
[ -z $var ] #===>echo $? --->1
[ -n $var ] #===>echo $? --->0
#-----
var="abc"
[ $var = "abc" ] #echo $? --->0##!!!!注意等号两边的空格不能少
[ $var = "abcd" ]#echo $? --->1
[ $var != "abcd" ]#echo $? --->0
补充
条件测试也除了使用以上的[]形式,也可以使用test命令,推荐使用[]
未定义的变量在shell中会被展开为空( 空而不是"" ),因此良好的shell编程习惯中推荐总是使用双引号来对变量取值,比如以下例子:
#变量vr不存在
var="abc"
[ $vr != "abcd" ] #err,报错
[ "$vr" != "abcd" ] #返回0
if分支
demo1
cd /
if [ -d bin ];then
> echo "It's a dictory"
> fi
It's a dictory
###
#! /bin/bash
if [ -f sample.sh ];then
echo "It's a file"
fi
###等价于
if [ -f sample.sh ]
then
echo "It's a file"
fi
demo2
#! /bin/bash
echo "Is it morning? please enter y or n:"
read ord
if [ $ord = "y" ];then
echo "good morning"
elif [ $ord = "n" ]; then
echo "good night"
else
echo "what black man question mark?"
exit 1
fi
if :; then
echo ": is always true" ### : 表示一条空指令且总为true
if
switch case
#说明:无switch,使用 ;; 防止case穿透(相当于break)
#! /bin/bash
echo "Is it morning? please enter yes or no:"
read ord
case "$ord" in
[yY][eE][Ss])
echo "good mao ni";;
[Nn][Oo])
echo "good evening";;
*)
echo "?????"
esac
循环
for
#! /bin/bash
for i in `ls`;do
echo "file name is $i,more about:"
ls -al $i
done
while
demo1
#! /bin/bash
echo "please enter the passwd"
read passwd
while [ "$passwd" != "secret" ];do
echo "sorry,passwd is not match,try again"
read passwd
done
demo2
#! /bin/sh
echo "while loop"
count=0
while [ "$count" -lt 10 ];do
echo "now it is $count"
count=$(($count+1))
done
break[n]可以跳出多层循环,continue同C语言相同。
demo2改进
#! /bin/sh
echo "while loop"
count=0
while [ "$count" -lt 10 ];do
echo "now it is $count"
count=$(($count+1))
if [ "$count" -eq 7 ];then
break
fi
done
命令行参数
##文件名为 argv.sh
#! /bin/bash
echo $0
echo $1
echo $2
echo $3
echo $4
echo "the argv's number is $#"
# $@为参数列表,可用于for循环
# $$ 当前进程的进程号
# $? 上一条命令的Exit status
# shift,命令行参数左移,自己测试(eg:处理一个左移一次)
bash argv.sh a1 a2 a3 a4 —>查看结果
也可以 chmod +x argv.sh
, ./argv a1 a2 a3 a4
查看结果
echo,printf,tee,重定向
-e 解析转义字符
运行以下命令查看区别:echo "hello\n"
和 echo -e "hello\n"
-n 不回车换行
运行以下命令查看区别:echo "hello"
和 echo -n "hello"
printf
printf命令有和echo相似的功能,具体使用请参考man
管道: 通过 | 把一个命令的输出传递到另一个命令做输入
tee
#>>代表在文件后面追加,不覆盖 > 代表覆盖文件内容写入
#当我们使用想将一个命令运行的结果输出到一个文件时
ls > out #此时屏幕上将不能显示运行结果,此时可以使用tee命令(输出到屏幕并保存到文件)
ls | tee out #此时将覆盖文件
ls | tee -a out #追加
重定向
cmd > file #标准输出重定向到新文件中
cmd >> file #标准输出重定向追加到文件中
cmd >file 2>&1 #标准出错也重定向到file文件中
cmd >>file 2>&1
cmd <file >fiel2 #标准输入/输出都重定向到文件中(cat < file )
cmd < &- #关闭标准输出
cmd >&fd #重定向到文件描述符中
由重定向引出来的两个关于nohup的非常常用的命令(nohup输出日志文件非常占用空间)
nohup commond >/dev/null 2>&1 &
不保存任何信息
nohup commond >/dev/null 2>log &
只输出错误信息到日志文件
函数
shell中的函数无返回值也无参数列表。
#定义函数
foo(){
echo "foo"
}
#调用
foo
#-------------传参demo,类似命令行参数-------
#! /bin/bash
foo(){
echo "$0"
echo "$1"
echo "$@"
}
foo 1 2 3
shell脚本的调试
-n #不执行,只检查语法(类似于nginx -t/ make -n)
-v #一边执行一边将出错打印出来
-x #跟踪程序执行信息,将每一条命令和执行结果输出出来
##
[root@iz2zeh46wfpirjtbp5x1xyz shell]# cat func3.sh
#! /bin/bash
echo "haha"
echo "ww"
[root@iz2zeh46wfpirjtbp5x1xyz shell]# bash -x func3.sh
+ echo haha
haha
+ echo ww
ww
#####部分片段
set -x #开启
echo "1"
echo "2"
...
set +x #关闭
#这样即可只对脚本的一部分片段进行追踪调试
正则表达式
扩展正则和基本正则
Basic正则与扩展正则类似,只是字符?+{}|()应解释为普通字符,如要表示上述特殊含义则需要加\转义
如果使用grep而不是egrep并且不加-E参数则遵照Basic正则来解释。
grep
grep -r “key word” 快速搜索目录下的关键字
….
find
find命令常用来找文件
find / -name “*init” 从根目录下查找名字以"init"结尾的文件
find ./ -size +2k 从当前目录下查找大于2K文件
find ./ -size +20M -size -40M 从当前目录下查找大于20M小于40M文件 (一个size一个限制)
(无单位默认为扇区大小,0.5K)
find ./ -type f 从当前目录下寻找类型为文件的 -type f,b,s
find ./ -maxdepth 1 -name “*” 列出当前文件夹下的文件/目录(不递归,且此参数应放在前边)
find命令不能和管道符同时使用,应使用exec替代
find ./ -maxdepth 1 -exec ls -l {} ; \;表示结束符
find ./ -maxdepth 1 -ok rm {} ; 交互版的exec,每次执行命令前询问y,n
find ./ -maxdepth 1 | xargs ls -ld 分批处理(内容过多时内存紧张,性能低等时)
xargs默认按照空格分隔,若返回结果中的有空格则不能正常运行
====>find ./ -maxdepth 1 -print0 |xargs -0 ls -lh
-atime|ctime|mtime: 天为单位(访问/修改/属性被修改 时间)
-amin|cmin|mmin
cd /var/log
find ./ -name "syslog*" -mtime +5 #5天前,,-5表示5天内
sed
流编辑器(stream editor),由于sed与vi同起源于UNIX的ed,因此两者有很多相似。
sed 将输入的内容读入缓冲区进行处理并输出。(默认并不修改源文件)
基本用法:
sed option 'script' file1 file2 ... 或者 sed option -f scriptfile file1 file2 ...
–version –help
-n,–silence,–quiet sed在所有脚本指令执行完成后将自动打印模式空间中的内容,这些选项可以屏蔽自动打印。
sed "s/at/ta/" test
##从test读入缓冲区并把内容中的at替换为 ta(注意结束的/不能少-e 允许多个脚本
-f 指定脚本文件
-i 直接在源文件中修改(慎用)
sed "s/at/ta/" test -i
##将test文件中的at替换为 ta
脚本的指令说明
>a , append 追加
>
>i,insert 插入
>
>d, delete 删除
>
>s, substitution 替换
sed "1,5d" test 将从test文件中读入的内容的1-5行删除
sed "2a DY不会编程" test 将从test文件中读入的内容第2行后加入 DY不会编程
对于脚本文件格式为 /pattern/action
,pattern表示正则表达式,action表示编辑操作。sed程序一行一行读入文件到缓冲区,如果某一行和pattern匹配则执行对应的action,如果一条命令没有pattern,则action处理每一行。
/pattern/p 打印符合pattern的行
/pattern/d 删除符合pattern的行
sed 's/bc/-&-' testfile
将testfile中的bc替换为 -bc-(即&代替bc)
awk
awk既可以进行行处理也可以进行列处理,但通常使用sed处理行。
awk缺省的行分隔符是换行,缺省的列分隔符是连续的空格和tab,但也可以自定义
ps aux|awk '{print $2}'
取进程号(打印第2列) $0表示全部
基本用法:类似于sed
[root@iz2zeh46wfpirjtbp5x1xyz tmp]# cat testfile
productA 12
productB 76
prductC 21
[root@iz2zeh46wfpirjtbp5x1xyz tmp]# awk '$2<75 {printf "%s %s\n",$0,"reorder"} $2>=75 { printf "%s \n",$0}' testfile
productA 12 reorder
productB 76
prductC 21 reorder
说明:
关于sed和awk的内容有很多(awk甚至有自己的语言),这里只简单介绍,具体可参考相关手册。
- Author: DY
- Link: http://4fan.top/posts/linux-shell%E7%BC%96%E7%A8%8B/
- License: This work is under a 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议. Kindly fulfill the requirements of the aforementioned License when adapting or creating a derivative of this work.