shell脚本命令

让.sh文件变为可执行的脚本文件命令:

1
chmod 777 xxx.sh

1.for循环

for循环一般格式为:

1
2
3
4
5
6
7
for 变量名 in 列表
do
command1
command2
...
commandN
done

   当变量值在列表里,for循环即执行一次所有命令,使用变量名获取列表中的当前取值。命令可为任何有效的shell命令和语句。in列表可以包含替换、字符串和文件名。in列表是可选的,如果不用它,for循环使用命令行的位置参数。

例如,顺序输出当前列表中的数字:

1
2
3
4
for loop in 1 2 3 4 5
do
echo "The value is: $loop"
done

输出:

1
2
3
4
5
The value is: 1
The value is: 2
The value is: 3
The value is: 4
The value is: 5

顺序输出字符串中的字符:

1
2
3
4
for str in 'This is a string'
do
echo $str
done

输出:

1
This is a string

2.获取当前时间,并进行格式转换的方法

1)原格式输出

1
2
time1=$(date)
echo $time1

输出:2018年 09月 30日 星期日 15:55:15 CST
2)时间串输出

1
2
3
1 #!bin/bash
2 time2=$(date "+%Y%m%d%H%M%S")
3 echo $time2

输出:20180930155515
3)格式转换输出

1
2
3
#!bin/bash
time3=$(date "+%Y-%m-%d %H:%M:%S")
echo $time3

输出:2018-09-30 15:55:15

1
2
3
#!bin/bash
time4=$(date "+%Y.%m.%d")
echo $time4

输出:2018.09.30

注意:
$(date "")类似的格式转换时,date后面要留有空格
time4=$(date "+%Y.%m.%d")time4变量赋值前后不能有空格

相关变量解释:

Y显示4位年份,如:2018;y显示2位年份,如:18。
m表示月份;M表示分钟。
d表示天;D则表示当前日期,如:1/18/18(也就是2018.1.18)。
H表示小时,而h显示月份。
s显示当前秒钟,单位为毫秒;S显示当前秒钟,单位为秒。

3.获取指定文件夹大小

3.1 获取指定文件夹大小

1
2
3
4
5
6
7
#/!bin/base
#设置文件夹地址(精确到文件夹名  如:需要获得file_name  文件夹的大小)
file_url="/home/file_name""
#获取[ 文件夹 ]大小(单位kb)
file_kb=$((`du --max-depth=1 ${file_url}|awk '{print $1}'`))
#打印输出文件夹大小
echo "file_size:$file_kb"

3.2 获取指定文件大小

1
2
3
4
5
6
#/!bin/base
#获取文件位置
file_url="/home/file_name/a.log"
#获取文件大小(单位kb)
file_kb=$((`ls -l ${file_url} | awk '{print $5}'`))
echo "file_size:$file_kb"

4.脚本变量$[#,@,0,1,2,*,$,?]含义

$# 是传给脚本的参数个数
$0 是脚本本身的名字
$1 是传递给该shell脚本的第一个参数
$2 是传递给该shell脚本的第二个参数
$@ 是传给脚本的所有参数的列表
$* 是以一个单字符串显示所有向脚本传递的参数,与位置变量不同,参数可超过9个
$$ 是脚本运行的当前进程ID号
$? 是显示最后命令的退出状态,0表示没有错误,其他表示有错误

$@, $*两者的区别:
   相同点:都是引用所有参数
   不同点:$* 和 $@ 都表示传递给函数或脚本的所有参数,不被双引号(“ “)包含时,都以”$1” “$2” … “$n” 的形式输出所有参数。但是当它们被双引号(“ “)包含时,”$*“ 会将所有的参数作为一个整体,以”$1 $2 … $n”的形式输出所有参数;”$@” 会将各个参数分开,以”$1” “$2” … “$n” 的形式输出所有参数。

shell中$*与$@的区别

5.if [ $# -ne 1 ];then命令

if [ $# -ne 1 ];then 是什么意思?

$# 是启动脚本时携带的参数个数
-ne 是不等于,这个语句的意思是“如果shell的启动参数不等于1个”
$# 表示提供到shell脚本或者函数的参数总数;
$1 表示第一个参数。
-ne 表示 不等于

另外:
整数比较

-eq 等于,如:if [“$a” -eq “$b” ]
-ne 不等于,如:if [“$a” -ne “$b” ]
-gt 大于,如:if [“$a” -gt “$b” ]
-ge 大于等于,如:if [“$a” -ge “$b” ]
-lt 小于,如:if [“$a” -lt “$b” ]
-le 小于等于,如:if [“$a” -le “$b” ]
< 小于(需要双括号),如:((“$a” < “$b”))
<= 小于等于(需要双括号),如:((“$a” <= “$b”))
大于(需要双括号),如:((“$a” > “$b”))
= 大于等于(需要双括号),如:((“$a” >= “$b”))

另外:$?是shell变量,表示”最后一次执行命令”的退出状态.0为成功,非0为失败.

参考链接:Linux 脚本编写基础知识

6.shell脚本实现scp文件传输

   scp是一个基于ssh的Linux环境下传输文件的好工具,但是使用shell脚本调用scp时会面临一个问题,即scp强制要求通过交互方式输入密码,而不像mysql等拥有-u -p选项。下面有两种方法帮助shell脚本跨过输入密码这个障碍。

6.1 建立机器间完全信任关系(这种方式没有操作过,不确定可靠性)

假设需要从机器A传输文件至机器B
1)在机器A上运行

1
ssh-keygen -t rsa

   上述命令会在~/.ssh/目录生成私钥证书id_rsa和公钥证书id_rsa.pub;
2)将公钥证书id_rsa.pub复制到机器B的用户根目录的.ssh子目录中,再将文件内容append到文件authorized_keys中。
   其实只要用一条单行命令就可以完成步骤2,它被commandlinefu.com的用户投票选为十大最酷的Linux单行命令之一:

1
ssh-copy-id  [-i [identity_file]]  [user@]machine

   identity_file是公钥证书的路径,默认情况下是~/.ssh/id_rsa.pub.

   如果要建立双方向的完全信任关系,还要从机器B到机器A再重复一遍上面的操作。
不过这样的方法并不完美,一是运维成本太高,二是机器间的安全屏障完全消失,安全代价太大,所以强烈推荐第二种方法。

6.2 expect脚本

   expect脚本是一种建立在tcl基础上的脚本语言,曝光率不高,却堪称shell脚本的好基友。expect脚本为交互而生,被设计为专门针对交互式程序的工具,常与对telnet、ftp、fsck、rlogin、tip、scp等配合使用。例如:

1
2
3
4
5
6
7
8
9
#! /bin/sh
/usr/expect/bin/expect -c "
spawn scp -r aiidc-parse-rundata-1.0-SNAPSHOT.jar root@172.16.16.184:/root
expect {
\"yes/no\" {send \"yes\r\"; exp_continue;}
\"*assword\" {set timeout 200; send \"aiidc@2019\r\"; exp_continue;}
}
expect eof
"

   这段脚本的含义是监听scp命令,如果输入包含*assword,则输入密码“passwd”;如果输入包含yes/no,输入yes并继续进行交互(exp_continue)。
   注:两个用户第一次scp连接时会提示“… Are you sure you want to continue connecting (yes/no)? …”,所以要考虑yes/no的情况。

6.3 使用sshpass免密操作

使用sshpass命令可以在脚本中提前输入密码便于直接运行命令:
eg:

1
2
sshpass -p aiidc@2019 scp -r aiidc-parse-rundata-1.0-SNAPSHOT.jar root@172.16.16.184:/root
sshpass -p aiidc@2019 ssh root@172.16.16.184 'cd /opt/parse-etl/kafka/'

   注意:在使用sshpass操作ssh命令时,通过ssh连接目标服务器后,如果有多个命令要执行,可将多条命令书写在一条命令上通过&&间隔,比如:

1
sshpass -p aiidc@2019 ssh root@172.16.16.184 'cd /opt/parse-etl/kafka/ && rm -rf aiidc-parse-rundata-1.0-SNAPSHOT.jar && ls && mv /root/aiidc-parse-rundata-1.0-SNAPSHOT.jar ./'

该命令的意思连接184服务器后,进入指定目录,先删除jar,然后将新jar移动到目标位置

ssh 用户名@目的主机地址 ‘要执行的命令或者脚本’
注意:

在调用脚本时,必须写全该脚本所在的全路径。
要执行的命令用单引号’ ’扩起来,引号扩起来的命令要和前面的内容写在一行,不能换行。

centos 7 jar包发布服务并开机启动

7.1 jar启动脚本start.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/sh
#先检查是否已启动
count=`ps -ef | grep '/opt/parse/api/dimension/aiidc-justice-dimension-1.0-SNAPSHOT.jar' | grep -v "grep" | wc -l`
#echo $count
if [ $count -gt 0 ]
then
echo "is running..."
else
#下面的cd不能少
cd /opt/api/zgjdev/
nohup java -jar -Dhanlp_properties_path=/opt/parse/api/dimension/config/hanlp.properties -Dspringfox.documentation.swagger.v2.host=172.16.16.153:80 -Xmx1024m /opt/parse/api/dimension/aiidc-justice-dimension-1.0-SNAPSHOT.jar >/opt/parse/api/dimension/log 2>/dev/null & echo $! > /opt/parse/api/dimension/pid
echo "started"
fi
cat /opt/parse/api/dimension/pid

启动的时候会生成pid文件(这个在制作启动服务地方会用到)
注意:start.sh里面路径都要写成绝对路径

7.2 制作启动服务

服务名称:xxx.service
以解析应用为例:parse.service

服务脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
[Unit]
Description=parse
After=syslog.target network.target remote-fs.target nss-lookup.target

[Service]
User=root
Type=simple
PIDFile=/opt/parse/api/dimension/pid
ExecStart=/opt/parse/api/dimension/start.sh
ExecStop=/bin/kill -15 $MAINPID

[Install]
WantedBy=multi-user.target

需要修改的地方
Description 修改为自己的名字或者描述
PIDFile 修改为自己服务启动后保存的pid文件路径
ExecStart 修改为自己的启动脚本路径

7.3 通过服务启动

将做好的服务拷贝到/etc/systemd/system/路径下

执行
systemctl daemon-reload
加入开机启动
systemctl enable data-application.service

看到这个表示加入开机自启成功

另:

1
2
3
4
#通过服务启动程序
systemctl start data-application.service
#通过服务停止程序
systemctl stop data-application.service

参考链接:Linux centos7下jar包发布成服务并开机自启