shell脚本是一种为 shell 编写的脚本程序, 一般文件后缀为 .sh
shell 的解释器种类众多:
shell 脚本中开头第一句的#!
告诉系统其后路径所指的程序即是解释此脚本文件的
shell 解释器
shell 变量命名:
shell 脚本中的变量默认都是全局的, 即其作用于从声明定义处一直到程序结束,如:
#!/bin/bash
func()
{
i="hello world" #变量定义是=左右不能有空格
}
func
echo ${i}
输出为:
hello world
想要声明局部变量使用local
关键字
value=${somevalues:othervalues}
#如果somevalues被定义了,则value=somevalues,否则values=othervalues
linux let
命令是 bash 中用于计算的工具, 用于执行一个或多个表达式, 变量计算中不需要加上 $ 来表示变量, 如果表达式中包含了空格或其他特殊字符, 则必须引起来
如:
i=0
let i++
#!/bin/bash
func()
{
while getopts "a:b:" opt
do
case ${opt} in
a) echo ${OPTARG}
;;
b) echo ${OPTARG}
;;
?) echo "wrong parameter"
esac
done
}
main()
{
func ${@}
}
main ${@}
?)
;;
相当于 break, 必须加esac
就是 case 反回来while getopts ":a:b:" opt
,这个:
表示getopts不返回错误OPTARG
变量保存当前参数,OPTIND
为argv
的当前索引值getopt
和getopts
用于 shell 脚本中分析脚本参数
getopt 所设置的全局变量:
定义完main函数, 使用 main "$@"
进行对main的调用
basepath=$(cd "$(dirname $0)"; pwd)
cut 命令用来从文件或者标准输入中读内容并截取特定部分送到标准输出
例如:
$ echo long ago test befor | cut -f 2,3 -d ' '
ago test
用于检查某个条件是否成立, 可以进行数值, 字符串和文件三个方面的比较
[] 是test命令的一种形式
eq
(equal的缩写),表示等于为真
ne
(not equal的缩写),表示不等于为真
gt
(greater than的缩写),表示大于为真
ge
(greater&equal的缩写),表示大于等于为真
lt
(lower than的缩写),表示小于为真
le
(lower&equal的缩写),表示小于等于为真
num1=100
num2=100
if test $[num1] -eq $[num2]
then
echo '两个数相等!'
else
echo '两个数不相等!'
fi
# 可以写为 if [ ${num1} -eq ${num2} ]
=
等于则为真!=
不相等则为真-z
字符串 字符串的长度为零则为真-n
字符串 字符串的长度不为零则为真例:
cd /bin
if test -e ./bash
then
echo '文件已存在!'
else
echo '文件不存在!'
fi
展开一个新的shell子程序, 所以括号中的变量为局部变量
a="123"
(a="456";echo "a=$a")
echo "a=$a
打印
456
123
a=$((4+5))
echo "a=$a"
$[]作用相同
a=5
((a++))
echo "a=$a"
if ((1+1>1));then
echo "1+1>1"
fi
[]
test 命令的另一种形式, 其中使用的命令见上一节
[[]]
是一个关键字, 比 []
更加通用,其中可以使用正则
例如:
if [[ 1.1 > 1.1 ]] || [[ 1.1 == 1.1 ]]; then
echo "ok"
fi
if [[ "123" == 12* ]]; then #右边是正则不需要引号
echo "ok"
fi
if [[ 2.1 > 1.1 ]]; then #支持浮点型
echo "ok"
fi
循环中 continue命令与break作用和其他语言中类似
语法为:
for a in "item1" "item2" "item3"
do
echo $a
done
例:
#输出当前目录下所有.sh结尾的文件
for a in `ls ./`
do
if [[ $a == *.sh ]]
then
echo $a
fi
done
语法:
while condition
do
command
done
例如:
#输出1~10000
int=1;
while(($int<=10000))do
echo $int
((int++))
done
shell也可以用户定义函数,然后在shell脚本中可以随便调用
所有函数在使用前必须定义。这意味着必须将函数放在脚本开始部分,直至shell解释器首次发现它时,才可以使用。调用函数仅使用其函数名即可。 语法格式如下:
[function] funname()
{
cmd....
[return int]
}
调用函数时可以向其传递参数。 在函数体内部,通过 $n 的形式来获取参数的值,例如,$1表示第一个参数,$2表示第二个参数… 调用的时候 ,函数名,参数直接用空格分割开
output()
{
echo "$1"
echo "$2"
}
output 1 2 #调用output
输出:
1
2
使用示例如下:
#!/bin/bash
#声明
declare -A dic
#赋值
dic=(
[node1]="value1"
[noid2]="value2"
)
# 打印元素个数
echo ${#dic[@]}
#遍历value
echo ${dic[*]}
#遍历key
echo ${!dic[*]}
#使用for循环遍历key
for key in ${!dic[*]}
do
echo "$key : ${dic[$key]}"
done
#字典添加一个新元素
dic+=([key4]="value4")
输出为
2
value1 value2
node1 noid2
node1 : value1
noid2 : value2
解释器要用
bsah
,sh
不支持declare
关键字及其语法
语法如下:
#数组
list=("value1" "value2" "value3")
#打印指定元素
echo ${list[2]}
#打印所有下标
echo ${!list[*]}
#打印所有数组元素
echo ${list[*]}
#数组增加一个元素
1. list+=("value4")
2. 下标添加
#for循环
for key in ${list[@]}
do
echo ${key}
done
输出如下:
value3
0 1 2
value1 value2 value3
value1 value2 value3 value4
value1
value2
value3
value4
注意,字符串长度从第0位开始计数
#!/bstrn/bash
str="123456789"
echo ${#str} #字符串长度
echo ${str:5} #从左边第五个字符开始到结束
echo ${str:2:4} #左边第二个字符开始四个字符
echo ${str:(-3):1} #倒数第三位
echo ${str:(-3)} #倒数三位
echo ${str:(-4):2} #倒数第四位开始两位
输出
9
6789
34
3456
7
789
67
以上方法应该基本能囊括所有的基本需求了
sed 's/^[ \t]*//g'
sed 's/[ \t]*$//g'
sed s/[[:space:]]//g
echo $(date +“%Y%m%d%H%M%S") #年月日时分秒
echo $(date +"%F %T) #年月日时分秒
输出格式不同
20190718135605
2019-07-18 13:56:05
使用格式为
获取今天之后的n天: date +"%Y%m%d" -d "+ n days"
获取今天之前的n天: date +"%Y%m%d" -d "- n days"
#!/bin/bash
today=$(date +"%Y%m%d")
yday=$(date +"%Y%m%d" -d "yesterday")
day=$(date +"%Y%m%d" -d "-2 days")
echo ${today}
echo ${yday}
echo ${day}
输出为
20190816
20190815
20190814
假如有一张student
表, 有id name score
等字段
1.
例:
HOST="127.0.0.1"
USER="root"
PASSWORD="..."
DBNAME="black_db"
TABNAME="student"
QUERY_SQL="SELECT id, name FROM ${TABNAME}"
while read -a row
do
echo ${row[0]} ${row[1]}
done< <(echo ${QUERY_SQL} | mysql -h${HOST} -u${USER} -p${PASSWORD} ${DBNAME})
输出
id name
1 lzj
2 balcklv
3 whitelv
4 lv
字段保存在对应的数组中打印
当然也可以赋值给变量保存供后续使用
BLACKDB="mysql -uroot -p123456lzj -h127.0.0.1"
SQL="select id, if (name = '', -1, name), money from blackDB.bankDB"
result=$(${BLACKDB} -N -e "${SQL}") #-N去掉字段名 -e接sql命令
echo ${result}
输出
1 lzj 2 blacklv 3 whitelv 4 lv
推荐第二种方法,第一种效率太低,速度太慢
可以参考Google开源项目风格指南
我的风格和其中的推荐也不是完全一样,不过有些还是应该听取其建议的,比如对于变量和函数的命名风格,对于变量的扩展格式等,说的就很对,应该吸取其建议
bc
命令, scale
指明精度res=$(echo "scale = 2; ${x} / ${y}" | bc) #保留两位小数,计算x / y的结果
if [ $(echo "${res} < 0.6" | bc) -eq 1 ]; then #比较res的值和0.6的大小
echo "hello world"
fi
但是bc
命令计算在计算0.xxx的时候,不会显示0
, 就加入算出来是0.1
, 值会是.1
, 虽然不妨碍计算和比较:
echo $(echo "${res} + 0.5" | bc) #不会妨碍结果,值为1.00
awk
#!/bin/bash
a=7
b=9
c=$(echo $a $b | awk '{print $1 / $2}')
echo $c
d=$(echo $a $b | awk '{printf("%.2f", $1/$2)}') #使用printf可以控制精度
echo $d
输出
0.777778
0.78
1 字符串判断
str1 = str2 当两个串有相同内容、长度时为真
str1 != str2 当串str1和str2不等时为真
-n str1 当串的长度大于0时为真(串非空)
-z str1 当串的长度为0时为真(空串)
str1 当串str1为非空时为真
2 数字的判断
int1 -eq int2 两数相等为真
int1 -ne int2 两数不等为真
int1 -gt int2 int1大于int2为真
int1 -ge int2 int1大于等于int2为真
int1 -lt int2 int1小于int2为真
int1 -le int2 int1小于等于int2为真
3 文件的判断
-r file 用户可读为真
-w file 用户可写为真
-x file 用户可执行为真
-f file 文件为正规文件为真
-d file 文件为目录为真
-c file 文件为字符特殊文件为真
-b file 文件为块特殊文件为真
-s file 文件大小非0时为真
-t file 当文件描述符(默认为1)指定的设备为终端时为真
3 复杂逻辑判断
-a 与
-o 或
! 非
该条收集于博客
shell 脚本对格式的要求比较严格,有时候很容易踩坑
第一次win下写完同步到linux后运行报了一堆莫名其妙的错误,意识到可能是文件存储格式不对,转一下就好了
date
和+
之间要有空格, 而+
和%F
之间不能有空格
echo $(date +%F)
echo $(date +"%F %T") #%F %T相当于后面跟了个字符串记得加引号
我们现在进行如下的判断
i=0
if [ ${i} -ne 0 ]; then
需要注意的是[]
中收尾要加空格
if [${i} -ne 0]; then #这样不加空格就会报错
字典的 declare 声明式如果是在函数内部,那么在函数内 / 外再为其赋值,都不对,echo
打印一下会发现其元素内容总是不对的,
但是如果·declare -A`的声明式在函数外部,那么一切正常
这个问题我还没明白为什么,按理说应该都是全局变量
日后明白了再更
欢迎解惑···
要注意必须是:a=b
不能是:a = b
=左右不能有空格
在 shell 中循环次数过多效率极低
一般将结果存入文件, 再使用 awk 读出
假设有数组array
#!/bin/bash
function ()
{
arr=$1
for i in ${arr[*]}; do #arr保存的是array中所有元素,以空格区分,并不是直接arr就是一个数组
echo $i
done
}
showArr "${array[*]}" #必须这样传递,不然只会传数组第一个元素
data=$(${MYSQL} -s -B -N -e "${SQL}")
if [ "x${data}" != "x" ]; then
echo "${data}" >> "file.tmp"
fi
awk 'BEGIN{FS=" "}{print $1,$2 ...$n "|" }' OFS="," file.tmp${i} >> file${i}
$1...$n
代表 n 个字段,FS=“ ”代表将结果中的空格分隔换为OFS=","的逗号分隔,并以 “|”结尾(当然也可以不要)
先将查询结果存入tmp
文件在使用awk
处理,不存入文件直接处理会丢失数据,多条结果只会处理第一条 (理所当然了,你的参数只有第一条的)
将 DB 的查询结果直接 echo 重定向写入文件却没有换行?
是因为没有加 ""
应该是 echo "${query_result}" > file