Linux的Shell种类众多,这里我们学习的是bash,也就是Bourne Again Shell,由于易用和免费,Bash在日常工作中被
广泛使用,同时,Bash也是大多数Linux系统默认的Shell。
文件名后缀通常是.sh
#!/bin/bash
#这里是注释
在一般情况下,人们并不区分 Bourne Shell和Bourne Again Shell,所以,在这里,我们可以看到#!/bin/bash,它同样
也可以改为#!/bin/sh。
shell单步调试:bash -x test.sh
shell语法检查:bash -n test.sh
变量
变量不需要声明,初始化不需要指定类型
变量命名
1:不能使用程序中的关键字(保留字)
2:只能使用数字,字母和下划线,且不能以数字开头
3:建议命令要通俗易懂
显示变量值使用echo命令 ,加上$变量名,也可以使用${变量名}
例如:echo $JAVA_HOME 或者 echo ${JAVA_HOME}
变量分类
本地变量:
只对当前shell进程有效的,对子进程和其它shell进程无效。
定义:VAR_NAME=VALUE 不能有空格
变量引用:${VAR_NAME}
取消变量:unset VAR_NAME
环境变量:
自定义的环境变量对当前shell进程及其子shell进程有效,对其它的shell进程无效
定义:export VAR_NAME=VALUE
对所有shell进程都有效需要配置到配置文件中
vi /etc/profile
source /etc/profile
局部变量:
函数调用结束,变量就会消失 对shell脚本中某代码片段有效
定义:local VAR_NAME=VALUE
位置变量:
$1,$2,.....${10}....
/tmp/test.sh a b
$0:脚本自身路径全名
$1:脚本的第一个参数
$2:脚本的第二个参数
特殊变量:
$?:接收上一条命令的返回状态码 如果执行成功,返回的状态码是0,执行失败的状态码在1-255之间 echo $?
$#:参数个数,可用于在脚本中用$#获取传入参数个数
$*:或者$@:所有的参数 ,可用于在脚本中用$*或$@获取传入的所有参数
$$:获取当前shell脚本的进程号,可以在脚本中使用$$获取当前脚本进程号
单引号、双引号、反引号
''单引号不解析变量
""双引号会解析变量
``反引号是执行并引用一个命令的执行结果,类似于$(...)
for循环
通过使用一个变量去遍历给定列表中的每个元素,在每次变量赋值时执行一次循环体,直至赋值完成所有元素退出循环
格式1
for ((i=0;i<10;i++))
do
...
done
格式2
for i in 0 1 2 3 4 5 6 7 8 9
do
...
done
格式三
for i in {0..9}
do
...
done
条件测试
bash条件测试
命令执行成功与否即为条件测试
test EXPR
[ EXPR ]:注意中括号和表达式之间的空格
整型测试:
-gt:大于:例如[ $num1 -gt $num2 ]
-lt:小于
-ge:大于等于
-le:小于等于
-eq:等于
-nq:不等于
字符串测试:
>:大于[ "$str1" \> "$str2" ]
<:小于
=
!=
算术运算
let varNamer=算术表达式
varName=$[算术表达式]
varName=$((算术表达式))
varName=`expr $num1 + $num2`
while/until循环
适用于循环次数未知,或不便用for直接生成较大的列表时
格式:
while 测试条件
do
循环体
done
如果测试条件为“真”,则进入循环,退出条件为,测试条件为假。
until循环的格式和while循环的格式一致,但是和while循环的意思相反,如果测试条件为假,则进入循环,退出条件为,测试条件为真
if判断
单分支
if 测试条件;then
选择分支
fi
双分支
if 测试条件
then
选择分支1
else
选择分支2
fi
多分支
if 条件1; then
分支1
elif 条件2; then
分支2
elif 条件3; then
分支3
...
else
分支n
fi
例子:
if [ $1 -eq 1 ]
then
echo "one"
elif [ $1 -eq 2 ]
then
echo "two"
else
echo "none"
fi
case判断
有多个测试条件时,case语句会使得语法结构更清晰
格式: case 变量引用 in
PATTERN1)
分支1
;;
PATTERN2)
分支2
;;
...
*)
分支n
;;
esac
PATTERN :类同于文件名通配机制,但支持使用|表示或者
a|b:a或者b
*:匹配任意长度的任意字符
?:匹配任意单个字符
[]:指定范围内的任意单个字符
例子:
#!/bin/bash
case $1 in
1)
echo "one"
;;
2)
echo "two"
;;
3)
echo "three"
;;
*)
echo "none"
;;
esac
自定义函数
function 函数名(){
....
}
引用自定义函数文件时,使用source func.sh有利于代码的重用性
定义fun1.sh
#!/bin/bash
function test(){
echo "hello world"
}
定义fun2.sh直接调用test()函数
#!/bin/bash
source /usr/local/fun1.sh
test
date
显示当前时间
格式化输出
date "+%Y-%m-%d %H:%M:%S"
格式%s表示自1970-01-01 00:00:00以来的秒数
date +%s
指定时间输出
date --date='2009-01-01 11:11:11'
指定时间输出
date --date='3 days ago'
获取指定日期自1970-01-01 00:00:00以来的秒数
date --date='2009-01-01 11:11:11' +%s
read
read命令接收标准输入(键盘)的输入,或者其他文件描述符的输入。得到输入后,read命令将数据放入一个标准变
量中。
格式
read VAR_NAME
read -p "Enter your name:" VAR_NAME 有提示信息Enter your name:
read如果后面不指定变量,那么read命令会将接收到的数据放置在环境变量REPLY中
read -t 5 -p "enter your name:" VAR_NAME 倒计时5秒钟
read -s -p "Enter your password: " pass 秘密的输入,看不到输入的内容
declare
用来限定变量的属性
-r 只读
#!/bin/bash
num=0
echo $num 输出0
declare -r num
num=1
echo $num 输出0
-i 整数:某些算术计算允许在被声明为整数的变量中完成,而不需要特别使用expr或let来完成。
#!/bin/bash
declare -i num
let num=1+1
echo $num
-a 数组
字符串操作
获取长度:${#VAR_NAME}
name=zhangsan
echo ${#name} 输出8
字符串切片
name=zhangsan
${string:offset:length}
echo ${name:2:3} 输出ang
取尾部的指定个数的字符
name=zhangsan
${string: -length}:注意冒号后面有空格
echo ${name: -3} 输出san
取子串:基于模式
${variable#*word} 从左往右取第一个word后面的字符串
name=zhangsan
echo ${name#*a} 输出ngsan
${variable##*word} 从左往右截取第二个word后面的字符串
name=zhangsan
echo ${name##*a} 输出n
${variable%word*} 从右往左取第一个word后面的字符串
name=zhangsan
echo ${name%a*} 输出zhangs
${variable%%word*} 从右往左取第二个word后面的字符串
name=zhangsan
echo ${name%%a*} 输出zh
查找替换:
${variable/pattern/substr}替换第一次出现
${variable//pattern/substr}替换所有的出现
${variable/#pattern/substr}替换行首的pattern,如果行首没有此字符串,则不替换
${variable/%pattern/substr}替换行尾的pattern,如果行尾没有此字符串,则不替换
查找删除
${variable/pattern}删除第一次匹配的字串
${variable//pattern}删除所有匹配的字串
${variable/#pattern}删除行首匹配的字串
${variable/%pattern}删除行尾匹配的字串
大小写转换
小-->大:${variable^^}
大-->小:${variable,,}
变量赋值操作
${parameter:-word}
如果变量parameter的值为空或者不存在,返回结果为word,此时变量parameter的值依然为空
${parameter:=word}
如果变量parameter的值为空或者不存在,返回结果为word,此时将word赋值给变量parameter
${parameter:?word}
如果变量parameter的值为空或者不存在,则把word当作错误信息返回。
${parameter:+word}
如果变量parameter的值存在,返回结果为word。如果变量不存在,则返回为空。
数组
定义:declare -a:表示定义普通数组
特点
支持稀疏格式
仅支持一维数组
数组赋值方式
一次对一个元素赋值a[0]=$RANDOM
一次对全部元素赋值a=(a b c d)
按索引进行赋值a=([0]=a [3]=b [1]=c)
命令替换 logs=($(ls /var/log/*.log)) 将/var/log/下所有的.log文件名作为数组元素存储在logs数组中
使用read命令read -a ARRAY_NAME
获取数组的长度
${#ARRAY[*]}
${#ARRAY[@]}
注意:${#ARRAY}表示获取数组中的第一个元素的长度,等于${#ARRAY[0]},等于$ARRAY
从数组中获取某一片段之内的元素
格式: ${ARRAY[@]:offset:number}
offset:偏移的元素个数
number:取出的元素的个数
${ARRAY[@]:offset}:取出偏移量后的所有元素
${ARRAY[@]}:取出数组中的所有元素
数组复制:(建议使用${ARRAY[@]})
$@:每个参数都是一个独立的串
$*:所有参数是一个串
删除元素:
unset ARRAY[index]
脚本后台运行,执行
sleep.sh & 但是如果关闭终端就会退出。因为终端关闭时终端会发送hangup命令停止该终端的所有进程
可以使用:nohup sleep.sh & 这样即使关闭终端脚本仍然继续执行着,输出日志可查看当前路径的nohup.out
标准输入、输出、错误
标准输入、输出、错误都是命令行,使用文件描述符0、1、2引用
cat > catfile < ~/.bashrc
ls >file 或者 ls 1>file 这样把每次的输出都会覆盖进file,如果想追加在原内容后面可以使用ls >> file
lk 2>file(lk是一个错误命令)
使用重定向可以把信息转换到其他位置
ls folder 2> /dev/null 将错误信息扔进黑洞
ls folder 1>/dev/null 2>&1 将正确信息和错误信息全扔掉
crontab定时器
使用crontab -e 添加定时任务
* * * * * echo 'date' >> /usr/local/date.log
每分钟输出时间信息,里面指定的文件或脚本必须是全路径
* * * * * echo 'date' >> /usr/local/shell.sh
每分钟执行shell.sh脚本,必须是全路径
可以使用tail -f /usr/local/date.log监控输出结果
crontab定时任务可以执行的前提是必须启动cron服务:service crond start。查看状态:service crowd status
ps用来显示当前shell启动的进程相关信息
ps -e 显示系统中所有进程
ps -ef | grep bash
jps显示所有java进程,但是有时候查看不到,可以使用ps -ef|grep java查看
在编写批量执行脚本,需要ssh到远程服务器执行的脚本时,由于ssh到远程服务器时,不会主动加载/etc/profile只会
加载~/.bashrc或/tmp/bashrc,所以需要将source /etc/profile命令添加到bashrc脚本中,批量脚本才能正确加载到远
程服务器的环境变量,脚本才能正确执行。
vi小技巧
非编辑模式下:
查找字符串:/string 找到后按n找下一个
按:输入数字,跳到指定行
复制一行:光标移到该行任意位置,按两下yy,复制完毕。再按p粘贴。要复制两行先按2,光标移到第一行按yy。
跳到最后一行:大写g