shell脚本
基础知识
linux打开终端提示符 username@hostname$ 或者root@hostname#
$ --普通用户
# --超级用户
echo $UID 结果为0则说明是超级用户
linux环境下的任何脚本语言都是以shebang(#! she为# bang为!)的特殊行作为起始的
例如 #!/bin/bash 字符#!被置于解释器路径之前, /bin/bash是bash的路径
运行脚本的方式
方式一:将脚本作为sh的命令行参数
例如:sh aa.sh 或者 sh /testshell/aa.sh
方式二:让shell独立运行 。前提是为脚本设置权限 ,shell程序会读取首行是否为#!/bin/bash 它会识别/bin/bash
并在内部以/bin/bash aa.sh来执行该脚本
[root@iZ2zedscyfod03wjkvxrk2Z testshell]# chmod 755 /testshell/aa.sh
[root@iZ2zedscyfod03wjkvxrk2Z testshell]# /testshell/aa.sh
this is a good start
[root@iZ2zedscyfod03wjkvxrk2Z testshell]#
在Bash中,每个命令是通过分号或者换行符来分割的
例如 cmd1;cmd2
等于
cmd1
cmd2
打印
echo
echo hello world ! 或者 echo 'hello world !' 或者echo "hello world \!" 双引号打印!需要转义
echo打印当打印不带双引号时候可以引用其他的值,带引号会原样输出
例如 aa=1 ;echo $aa 会输出1 而 echo '$aa' 会输出 $aa
echo打印会自动添加换行符
printf
printf不会自动带换行符,需要手动添加
例如 printf "%-5s %-10s %-4s\n" this is ajod
%-5s 格式为左对齐宽度为5的字符串对齐(-标识左对齐)
%-4.2f .2指定保存2位小数位
环境变量
查询指定pid进程的环境变量
cat /proc/$PID/environ
例如cat /proc/3255/environ | tr '\0' '\n' --tr用于输出格式化用null(\0)分割成name=value
查询进程的进程ID
pgrep java
变量打印
$var 或 ${var} 原样打印变量var的值 ${#var} 打印var的长度
export 设置环境变量 仅限于当前登录操作有效,其他的会失效
export PATH="$PATH:/home/jdk/bin" --在path添加一条新路径
识别当前shell版本
echo $SHELL 或者echo $0
数学运算
基础运算
let var0=var1+var2 let var0++ let var0-- let var0+=2 let var0-=2
var0=$[var1 + var2] var0=$[ $var1 + 1] var0=$((var1 + var2))
var0=`expr 3 + 4` var0=$(expr $var0 + 5)
浮点数运算 计算工具bc
echo "4 *0.25" | bc
echo "scale=2;3/8" |bc --scale=2 小数点设置为两位
echo "obase=2;100" |bc --obase=2 十进制转二进制
echo "obase=10;ibase=2;1100100"|bc 二进制转十进制
echo "sqrt(100)" |bc 平方根
echo "10^10"|bc 平方
文件输入输出
> 将文本重定向到文件,会清空文件,在写入内容
>> 将文本重定向到文件,不会清空文件,在后面追加内容
标准输入 0 stdin 1> 等同于 .> 1>> 等同于>>
标准输出 1 stdout
标准错误 2 stderr
将stderr转换成stdout 使得stderr和stdout都被重定向到out.txt文件
cmd 2>&1 out.txt 或者 cmd &>out.txt
可以将stderr重定向到/dev/null ,这是个特殊的设备文件,接收到的任何数据都会被丢弃,称为位桶或者黑洞
tee 命令 -- 一方面将数据重定向到文件,一方面 提供重定向数据的副本作为后续命令的stdin
command | tee file1 file2
例如cat * | tee out.txt | cat -n
第一步先将cat出来的内容输出值out.txt ,第二部将cat出来的内容没一行加上行号写入stdout
< 操作符用于从文件中读取至stdin
数组
数组的定义
arr=(0 1 2 3 4 5)
arr[0]="0" arr[1]="1" arr[2]="2"
arr=([a]=a [b]=b)
数组的打印
${arr[0]} ${arr[*]} --打印单个值和所有值
打印数组的索引列表
${!arr[*]}
别名
格式: alias new_cmd='cmd'
alias的别名是暂时的,关闭终端会失效,alias可以为所有的命令创建别名,当不需要使用别名而忽略别名时,可以使用\进行转义,使用真实的命令
日期
日期 date
date "+%Y:%B:%d:%H:%M:%S"
tput
打印行数和tput cols tput lines
aa.sh脚本如下
#!/bin/bash
tput sc
count=0;
while true;
do
if [ $count -lt 40 ];
then let count++;
sleep 1;
#tput rc
#tput ed 删除当前光标位置到行尾的所有内容
set -x
echo -n $count;
set +x
else exit 0;
fi
done
脚本调试
bash -x aa.sh aa.sh脚本见上面,选项-x ,启动跟踪调试shell脚本
也可以将#!/bin/bash 改成 #!/bin/bash -xv
set -x :在执行是显示参数和命令
set +x : 禁止调试
set -v : 当命令进行读取是显示
set +v : 禁止打印输出
函数
定义函数:
function aa(){
echo $1;
echo $2;
} 或者 aa(){} 函数里面调用参数 $1(第一个参数) $2(第二个参数) $n(第n个参数)
调用函数: aa 10 20 (函数名后面带参数)
读取命令返回值 $? 退出为0 没退出部位0
if [ $? -eq 0 ] 判断当前命令是否为已退出
管道
管道操作符 |
输入通常是通过stdin或者参数传递给命令,输出要么出现stdout,要么出现stderr,当我们结合多个命令时,同时将stdin用于输入,stdout用于输出。这些 命令被称为过滤器,我们使用管道(pipe)来连接每一个过滤器,管道操作符是|
cmd1 | cmd2 | cmd3
子shell命令
cmd_output=$(cmd) 或者 cmd_output=`cmd` 储存子shell命令在直接调用
read读取
read -n 2 var -- 从键盘输入的读取两个字符存入var里面
read -s var -- 用不回显的方式读取键盘输入 存入var里面
read -p "enter your password" var --提示输入信息 然后读取输入的信息存入var里面
read -t 3 var --三秒内读取键盘输入内容存入var里面
read -d ":" var --读取键盘输入,遇到:结束读取,并把读取的内容存入var里面
字符分割符
内部字段分隔符(IFS),在处理文本数据时,可以通过特定的符号把文本分成多个,IFS默认是空白字符串(换行符、制表符或者空格)
#!/bin/bash
data="name,sex,blue,age" --定义字符串
oldIFS=$IFS --吧原始的IFS值存入oldIFS
IFS=, --吧,赋值给IFS
for item in $data; --分割符切割data,循环切割之后的内容
do
echo Item: $item --打印切割之后的值
done
IFS=$oldIFS --吧原始的IFS值重新赋值回去
循环语句
for语法
for var in list #list 可以试字符串,也可以是个列表 {1..10} {a..z} {A..Z} 可以快速生成数字列表
do
cmd # 获取变量$var的值进行操作
done
while语法
while condition #会一直循环直到跳进不成立
do
cmd
done
aa=1
while [ $aa -lt 6 ]
do
echo $aa
let aa+=1
done
until语法
until condition #会一直循环到给定的条件为真
do
cmd
done
比较和测试
if语法
if condition # &&逻辑与 ||逻辑或
then
cmd
elif condition
then
cmd
else
cmd
fi
运算符
-gt:大于 -lt:小于 -eq:等于 -ge:大于等于 -le:小于等于
比较 [ $var -eq 0 ] #当等于0时返回真 与[]之间要有空格,不然会报错
[$var -ne 0] #为非时返回真
[ $var -eq 0 ] or [ $var -eq 0 ] # 或运算
文件系统测试相关
[ -f $file_var] #变量名包含正常的文件路径或文件名,则返回真
[ -x $var ] #变量名包含的文件可执行,则返回真
[ -d $var ] #变量名包含的是目录,则返回真
[ -e $var ] #变量名包含的文件存在,则返回真
[ -c $var ] #变量名包含的是一个字符设备文件的路径,则返回真
[ -b $var ] #变量名包含的是一个块设备文件的路径,则返回真
[ -w $var ] #变量名包含的文件可写,则返回真
[ -r $var ] #变量名包含的文件可读,则返回真
[ -L $var ] #变量名包含的是一个符号链接,则返回真
字符串比较
等于 [[ $str1 = $st2 ]] 或者 [[ $str1 == $st2 ]]
大于 [[ $str1 > $st2 ]] 不等于 [[ $str1 != $st2 ]] 小于 [[ $str1 < $st2 ]]
空字符串 [[-z $str1]] 为空返回真
空字符串 [[-n $str1]] 非空返回真
if [[ $str1 > $st2 ]] && [[ $str1 > $st2 ]]; #多个条件组合 && ||
then
cmd;
fi
test命令 可以避免过去括号
if test $str1 > $st2 && test $str1 > $st2 ; #多个条件组合 && ||
then
cmd;
fi
grep (global regular expression) 命令用于查找文件里符合条件的字符串或正则表达式,若不指定任何文件名称,或是所给予的文件名为 -,则 grep 指令会从标准输入设备读取数据。
语法:
grep [options] pattern [files]
或
grep [-abcEFGhHilLnqrsvVwxy][-A<显示行数>][-B<显示列数>][-C<显示列数>][-d<进行动作>][-e<范本样式>][-f<范本文件>][--help][范本样式][文件或目录...]
pattern - 表示要查找的字符串或正则表达式。
files - 表示要查找的文件名,可以同时查找多个文件,如果省略 files 参数,则默认从标准输入中读取数据。
常用选项
-i :忽略大小写进行匹配
-v :反向查找,只打印不匹配的行
-n :显示匹配行的行号
-r :递归查找子目录中的文件
-l :只打印匹配的文件名
-c :只打印匹配的行数
例子:
grep hello file.text #在file.text中匹配hello,并打印匹配的行
echo "hello wolrd" | grep -c world #在标准输入中查找字符串“world”,并只打印匹配的行数
grep test *file #在当前目录中,查找后缀有 file 字样的文件中包含 test 字符串的文件,并打印出该字符串的行
grep -r update /etc/acpi #以递归的方式查找符合条件的文件。查找指定目录/etc/acpi及其子目录中包含字符串 update的文件
grep -v hello *test* #反向查找。查找文件名中包含test,但文件中不包含hello字符串的文件
find命令
find命令用于在指定的目录下查找文件和目录
语法
find [路径] [匹配条件] [动作]
路径:
-name pattern :按文件名查找。支持使用通配符*和?
-type type :按文件类型查找,可以试f(普通文件),d(目录),l(符号链接)等。
-size [+-]size[cwbkMG]:按文件大小查找,支持使用+或-表示大于或小于指定大小,单位可以是c(字节),b(块数),k(KB),M(MB),或G(GB)
-mtime days:按修改时间查找,支持使用+或-表示在指定天数前或后,days是一个整数表示天数。
-user username:按文件所有者查找
-group groupname:按文件所属组查找
动作:可选的,用于对匹配到的文件执行操作,比如删除,赋值等。
find命令中用于时间的参数如下:
-amin m:查找n分钟内被访问过的文件
-atime n:查找在n*24 小时内被访问过的文件
-cmin n:查找在n分钟内状态发生改变的文件(例如权限)
-ctime n:查找在n*24小时内状态发生变换的文件(例如权限)
-mmin n:查找在n分钟内被修改过的文件
-mtime n:查找在n*24小时内被修改过的文件
在上述参数中n可以是正数,负数,零。正数表示在执行的时间内修改或访问过的文件,负数表示在执行的时间前修改或访问过的文件,零表示在当前时间点上修改或访问或的文件。
例子:
find . -name file.txt #查找当前目录名为file.txt的文件
find . -name "*.log" #查找当前目录下后缀的.log的文件
find . -type f #列出当前目录下所有的文件
find . -size +2k #列出大于2kb的文件
find . -type f -mtime -7 -ok rm {} \; #删除当前目录及下属目录中的文件,且文件更改时间必须在七天内。 -ok 安全模式删除,会再次询问是否需要删除。
find . -type f -name "*.log" -exec rm {} \; #删除当前目录及下属目录中的以log结尾的文件。会直接删除不会再次确认。
find . -name "*.log" -exec ls -l {} \; #列出当前文件夹以及下属文件夹以log结尾的文件
上述例子中
-exec 选项允许你执行一个命令
{}将会被匹配到的文件替代
\;表示命令结束
awk命令
awk是处理文本的语言,可以处理分析文本
语法:
awk options 'pattern {action}' file
options:是一些选项,用于控制 awk 的行为。
pattern:是用于匹配输入数据的模式。如果省略,则 awk 将对所有行进行操作。
{action}:是在匹配到模式的行上执行的动作。如果省略,则默认动作是打印整行。
options参数:
-F <分割符>或者 --field-separator =<分隔符> 分隔符,不填默认是空格。
-v <变量名>=<值>:设置awk内部的变量值,可以使用该选项将外部值传递给awk脚本中的变量
-f <脚本文件>: 执行一个包含aek脚本的文件,这样可以在文件中编写较大的awk脚本
-v 或者 --version:显示awk的版本信息
-h 或者 --help:显示awk的帮助信息
例子:
awk '{print}' aa.log #打印aa.log文件的每一行
awk '{print $1,$2}' aa.log # aa.log每一行用默认的空格分隔符分割成多列,打印每行的第一列和第二列
awk -F ';' '{print $1,$2}' aa.log #指定分割符为;每行打印第一个和第二个字段,用空格拼接
awk -F ';' '{print $1 $2}' aa.log #指定分割符为;每行打印第一个和第二个字段,两个字段拼接在一起
awk -F '[;,]' '{print $1,$2}' aa.log #指定多个分割符,先用;分割,再用,分割
awk '{print NR,$0}' aa.log #打印每行的行号 NR 行号 从1开始, $0 每行完整的输入记录
awk -f aa.awk aa.log #指定awk脚本
awk '$1>2' aa.log # 打印每行第一个字段大于2的行
awk '$1>2 && $1=="3第" {print $1,$2"999"}' aa.log #选出第一个字段大于2 且等于3第;打印选出的每行的第一个和第二个字段