【转载】书写优雅的shell脚本

书写优雅的shell脚本(一)- if语句

      使用 unix/linux 的程序人员几乎都写过 shell 脚本,但这其中很多人都是为了完成功能而在网上找代码段,这样写出来的 shell 脚本在功能方面当然是没有什么问题,但是这样的方式不能写出优雅的 shell 脚本。 从今天开始,就将自己平时在书写 shell 脚本过程中的经历做一总结,力图形成一个系列 --- “书写优雅的 shell 脚本”。 

在此,对“优雅”一词的定义有 4 点: 

  • 健壮
  • 结构清晰
  • 性能好
  • 力求简单

好了,废话不多说,开始今天的主题:if 语句 

1.1 if 判断式

格式一: 

?


1

2

3

if [ 条件判断一 ] &&(||) [ 条件判断二 ]; then

    xxx

fi

格式二: 

?


1

2

3

4

5

if [ 条件判断一 ] &&(||) [ 条件判断二 ]; then

    xxx

else

    xxx

fi

格式三: 

?


1

2

3

4

5

6

7

8

if [ 条件判断一 ] &&(||) [ 条件判断二 ]; then

    xxx

elif [ 条件判断三 ] &&(||) [ 条件判断四 ]; then

    xxx

...

else

    xxxx

fi

1.2 if 中的二元比较

1.2.1 整数比较

  • -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 ]
  • >        大于,如:         if [ $a > $b ]
  • >=     大于等于,如:        if [ $a >= $b ]

注:以上其实不是健壮的代码,上面这些代码在有些情况下会存现错误提示,而真正健壮的是使用双括号来表示,即 if [[ $a -eq $b ]] 。 
这是为何?做个测试如下: 

?


1

2

3

[root@Betty Shell]# a=;b=3;

[root@Betty Shell]# if [ a -gt $b ]; then echo "true"; fi

-bash: [: a: integer expression expected

而改为 

?


1

[root@Betty Shell]# if [[ a -gt $b ]]; then echo "true"; fi

将不再报错,这也是我们所期望的。
注:原文中改为 if [[ a > $b ]]; then echo "true"; if ,这种改法是错误的,将永远输出 true 。 ) 
      究其原因,是因为如果变量 a 值为空(由于 shell 是弱类型语言,对变量赋值都是当字符串对待),那么就成了 [ -gt 3 ] ,显然 [ 和 $b 不相等,并且缺少了 [ 符号,所以报了这样的错误。当然不总是出错,如果变量 a 值不为空,程序就正常了,所以这样的错误还是很隐蔽的。 

1.2.2 字符串比较

  • 等于,如:if [ $a = $b ] 或 if [ $a == $b ] ,与 = 等价
  • 不等于,如:if [ $a != $b ]
  • 大于,在 ASCII 字母顺序下。如:if [ $a \> $b ]
  • 小于,在 ASCII 字母顺序下。如:if [ $a \< $b ] 

注意:要使用转义符“\”。 

1.2.3 文件比较

  • [ 文件1 -nt 文件2 ] 为真,如果文件 1 被 changed more recently than 文件 2 ,或者如果文件 1 存在,而文件 2 不存在。
  • [ 文件1 -ot 文件2 ] 为真,如果文件 1 比文件 2 旧, 或者文件 2 存在而文件 1 不存在。
  • [ 文件1 -ef 文件2 ] 为真,如果文件 1 和 文件 2 均 refer to the same device and inode numbers。

1.2.4 表达式比较

  • [ 表达式1 -a 表达式2 ] 如果表达式 1 和表达式 2 同时为真则为真 。
  • [ 表达式1 -o 表达式2 ] 如果表达式 1 或者表达式 2 其中之一为真则为真。

1.3 if 中的一元比较

  • [ -a 文件 ] 如果文件存在,则为真。
  • [ -b 文件 ] 如果文件存在,并且是一个块文件,则为真。
  • [ -c 文件 ] 如果文件存在,并且是一个字符文件,则为真。
  • [ -d 文件 ] 如果文件存在,并且是一个目录,则为真。
  • [ -e 文件 ] 如果文件存在,则为真。
  • [ -f 文件 ] 如果文件存在,并且是一个普通文件,则为真。
  • [ -g 文件 ] 如果文件存在,并且已经设置了 SGID 位,则为真。
  • [ -h 文件 ] 如果文件存在,并且是一个符号连接,则为真。
  • [ -k 文件 ] 如果文件存在,并且其 sticky 位已经设置,则为真。
  • [ -p 文件 ] 如果文件存在,并且是一个命名管道,则为真。
  • [ -r 文件 ] 如果文件存在,并且是可读的,则为真。
  • [ -s 文件 ] 如果文件存在,并且比零字节大,则为真。
  • [ -t FD ]   如果文件存在,并且文件描述符已经打开,且指向一个终端,则为真。
  • [ -u 文件 ] 如果文件存在,并且已经设置了其 SUID(set user ID) 位,则为真。
  • [ -w 文件 ] 如果文件存在,并且文件是可写的,则为真。
  • [ -x 文件 ] 如果文件存在,并且文件是可执行的,则为真。
  • [ -O 文件 ] 如果文件存在,并且属于有效用户 ID ,则为真。
  • [ -G 文件 ] 如果文件存在,并且属于有效组 ID ,则为真。
  • [ -L 文件 ] 如果文件存在,并且是一个符号连接,则为真。
  • [ -N 文件 ] 如果文件存在,并且如果 has been modified since it was last read ,则为真。
  • [ -S 文件 ] 如果文件存在,并且是一个 socket ,则为真。
  • [ -o 选项名 ] 如果 shell 选项 "选项名" 开启,则为真。
  • [ -z STRING ] 如果 "STRING" 的长度是零,则为真。
  • [ -n STRING ] 或者 [ STRING ] 如果 "STRING" 的长度是非零值,则为真。
  • [ ! EXPR ] 如果 EXPR 为假,则为真。
  • [ ( EXPR ) ] 返回 EXPR 的值。 这样可以用来忽略正常的操作符优先级。

===  我是YOYO的分隔线 === 

书写优雅的shell脚本(二)- `dirname $0`

      在命令行状态下单纯执行 $ cd `dirname $0` 是毫无意义的。因为其 cd 到的路径是 cd 命令执行的当前路径的。 
      这个命令写在脚本文件里才有作用,其返回该脚本文件所在目录的路径,并可以根据这个目录来定位所要运行程序的相对位置(绝对位置除外)。 
在 /home/admin/test/ 下新建 test.sh 内容如下: 

?


1

2

3

4

#!/bin/sh

 

cd `dirname $0`

echo `pwd`

然后返回到 /home/admin/ 执行 

?


1

sh test/test.sh

运行结果: 

?


1

/home/admin/test

      这样就可以知道一些和脚本一起部署的文件的位置了,只要知道相对位置就可以根据这个目录来定位,而可以不用关心绝对位置。这样脚本的可移植性就提高了,扔到任何一台服务器,(如果是部署脚本)都可以执行。 

===  我是乐观的分隔线 === 

书写优雅的shell脚本(三) - shell中exec解析

参考:《linux命令、编辑器与shell编程》、《unix环境高级编程》 

exec 和 source 都属于 bash 内部命令(builtins commands),在 bash 下输入 man exec 或 man source 可以查看所有的内部命令信息。 
bash shell 的命令分为两类:外部命令内部命令。外部命令是通过系统调用或独立的程序实现的,如 sed、awk 等等。内部命令是由特殊的文件格式(.def)所实现,如 cd、history、exec 等等。 

      在说明 exec 和 source 的区别之前,先说明一下 fork 的概念。 fork 是 linux 的系统调用,用来创建子进程(child process)。子进程是父进程(parent process)的一个副本,从父进程那里获得一定的资源分配以及继承父进程的环境。子进程与父进程唯一不同的地方在于 pid(process id)。环境变量(传给子进程的变量,遗传性是本地变量和环境变量的根本区别)只能单向从父进程传给子进程。不管子进程的环境变量如何变化,都不会影响父进程的环境变量。  

      有两种方法执行 shell script 。一种是新产生一个 shell,然后执行相应的 shell script ;另一种是在当前 shell 下执行,不再启用其他 shell 。 新产生一个 shell 然后再执行 script 的方法是在 script 文件开头加入以下语句 

?


1

#!/bin/sh

      一般的 script 文件(.sh)即是这种用法。这种方法先启用新的 sub-shell(新的子进程),然后在其下执行命令。 另外一种方法就是上面说过的 source 命令,不再产生新的 shell,而在当前 shell 下执行一切命令。 
      source 命令即点(.)命令。 在 bash 下输入 man source,找到 source 命令解释处,可以看到解释 ”Read and execute commands from filename in the current shell environment and …”。从中可以知道,source 命令是在当前进程中执行参数文件中的各个命令,而不是另起子进程(或 sub-shell)。 
      在 bash 下输入 man exec ,找到 exec 命令解释处,可以看到有”No new process is created.”这样的解释,这就是说 exec 命令不产生新的子进程。

exec 与 source 的区别是什么呢?
      系统调用 exec 是以新的进程去代替原来的进程,但进程的 PID 保持不变。因此可以这样认为,exec 系统调用并没有创建新的进程,只是替换了原来进程上下文的内容,即原进程的代码段,数据段,堆栈段被新的进程所代替。 

一个进程主要包括以下几个方面的内容: 

  • 一个可以执行的程序
  • 与进程相关联的全部数据(包括变量,内存,缓冲区)
  • 程序上下文(程序计数器 PC ,保存程序执行的位置)

      执行 exec 系统调用,一般都是这样,用 fork() 函数新建立一个进程,然后让进程去执行 exec 调用。我们知道,在 fork() 建立新进程之后,父进各与子进程共享代码段,但数据空间是分开的,但父进程会把自己数据空间的内容 copy 到子进程中去,还有上下文也会 copy 到子进程中去。而为了提高效率,采用一种写时 copy 的策略,即创建子进程的时候,并不 copy 父进程的地址空间,父子进程拥有共同的地址空间,只有当子进程需要写入数据时(如向缓冲区写入数据),这时候会复制地址空间,复制缓冲区到子进程中去。从而父子进程拥有独立的地址空间。而对于 fork() 之后执行 exec 后,这种策略能够很好的提高效率,如果一开始就 copy ,那么 exec 之后,子进程的数据会被放弃,被新的进程所代替。 

exec 与 system 的区别是什么呢? 

  • exec 是直接用新的进程去代替原来的程序运行,运行完毕之后不回到原先的程序中去。
  • system 是调用 shell 执行你的命令。

system = fork + exec + waitpid 

执行完毕之后,回到原先的程序中去。继续执行下面的部分。 
总之,如果你用 exec 调用,首先应该 fork 一个新的进程,然后 exec 。而 system 不需要你 fork 新进程,已经封装好了。 

===  我是九喇嘛的分隔线 === 

书写优雅的shell脚本(四) - kill命令的合理使用

... 
kill -0 PID 向某一进程发送一个无效的信号,如果该进程存在(能够接收信号),则执行 echo $? 得到 0 ;否则为 1 。由此可以知道进程是否存在。 
... 

===  我是六道斑的分隔线 === 

书写优雅的shell脚本(五)- shell中(())双括号运算符

      在使用 shell 的逻辑运算符”[]”使用时候,必须保证运算符与算数之间有空格。 四则运算也只能借助:let 、expr 等命令完成。 今天讲的双括号”(())”结构语句,就是对 shell 中算数及赋值运算的扩展。  

5.1 语法

((表达式1,表达式2…))  

特点:  

  • 在双括号结构中,所有表达式可以像 c 语言一样,如:a++、b-- 等。 
  • 在双括号结构中,所有变量可以不加入“$”符号前缀。 
  • 双括号可以进行逻辑运算,四则运算 
  • 双括号结构 扩展了 for 、while 、if 条件测试运算 
  • 支持多个表达式运算,各个表达式之间用“,”分开 

5.2 使用实例

5.2.1 扩展四则运算 

代码如下: 

?


1

2

3

4

5

6

7

8

#!/bin/sh

a=1;

b=2;

c=3;

((a=a+1));

echo $a;

a=$((a+1,b++,c++));

echo $a,$b,$c

运行结果:  

?


1

2

3

# sh testsh.sh

2

3,3,4

双括号结构之间支持多个表达式,然后加减乘除等 c 语言常用运算符都支持。如果双括号带 $ ,将获得表达式值,赋值给左边变量。  

5.2.2 扩展逻辑运算 

代码如下: 

?


1

2

3

4

5

6

#!/bin/sh

a=1;

b="ab";

echo $((a>1?8:9));

((b!="a"))&& echo "err2";

((a<2))&& echo "ok";

运行结果:  

?


1

2

3

9

err2

ok

5.2.3 扩展条件测试运算(if)

代码如下: 

?


1

2

3

4

5

6

7

8

a=1

b=2

if ((a<b));then

    echo "true";

fi

if ((a>b));then

    echo "false"

fi

运行结果:

?


1

true

5.2.4 扩展流程控制语句(逻辑关系式) 

代码如下:  

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

#!/bin/sh

num=100;

total=0;

for((i=0;i<=num;i++));

do

    ((total+=i));

done

echo $total;

 

total=0;

i=0;

while((i<=num));

do

    ((total+=i,i++));

done

echo $total;

 

if((total>=5050));then

    echo "ok";

fi

运算结果: 

?


1

2

3

5050

5050

ok

有了双括号运算符 [[]] 、[] 、test 等逻辑运算,以及 let 、expr 等就不是必须的了。 

===  我是如丧的分隔线 === 

书写优雅的shell脚本(六)- shell中的命令组合(&&、||、())

      shell 在执行某个命令的时候,会返回一个返回值,该返回值保存在 shell 变量 $? 中。当 $? == 0 时,表示执行成功;当 $? == 1 时,表示执行失败。 
      有时候,下一条命令依赖前一条命令是否执行成功。比如在成功地执行一条命令之后再执行另一条命令,或者在一条命令执行失败后再执行另一条命令等。shell 提供了 && 和 || 来实现命令执行控制的功能,shell 将根据 && 或 || 前面命令的返回值来控制其后面命令的执行。 

6.1 &&(命令执行控制)

语法格式如下: 
command1 && command2 [&& command3 ...] 

  • 命令之间使用 && 连接,实现逻辑与的功能。
  • 只有在 && 左边的命令返回真(命令返回值 $? == 0),&& 右边的命令才会被执行。
  • 只要有一个命令返回假(命令返回值 $? == 1),后面的命令就不会被执行。

示例 1 : 

?


1

[root@Betty ~]# cp ~/workspace/1.txt ~/1.txt && rm ~/workspace/1.txt && echo "success"

示例 1 中的命令首先从 ~/workspace 目录复制 1.txt 文件到 ~ 目录;执行成功后,使用 rm 删除源文件;如果删除成功则输出提示信息。  

6.2 ||(命令执行控制)

语法格式如下: 
command1 || command2 [|| command3 ...] 

  • 命令之间使用 || 连接,实现逻辑或的功能。
  • 只有在 || 左边的命令返回假(命令返回值 $? == 1),|| 右边的命令才会被执行。这和 c 语言中的逻辑或语法功能相同,即实现短路逻辑或操作。
  • 只要有一个命令返回真(命令返回值 $? == 0),后面的命令就不会被执行。

示例 2 : 

?


1

2

3

[root@Betty ~]# rm ~/workspace/1.txt || echo "fail"        

rm: 无法删除"/root/workspace/1.txt": 没有那个文件或目录

fail

在示例 2 中,如果 ~/workspace 目录下不存在文件 1.txt,将输出提示信息。 

示例 3 : 

?


1

2

3

[root@Betty ~]# rm ~/workspace/1.txt && echo "success" || echo "fail"

rm: 无法删除"/root/workspace/1.txt": 没有那个文件或目录

fail

在示例 3 中,如果 ~/workspace 目录下存在文件 1.txt,将输出 success 提示信息;否则输出 fail 提示信息。  

      shell 提供了两种方法 () 和 {} 实现将几个命令合作一起执行,代替独立执行。这种方式并不能控制命令是否需要执行,仅是将多个单独的命令组合在一起执行最终命令的返回值将由最后一条命令的返回值来决定。  

6.3 ()(命令组合)

语法格式如下: 
(command1;command2[;command3...]) 

  • 一条命令需要独占一个物理行,如果需要将多条命令放在同一行,命令之间使用命令分隔符(;)分隔。执行的效果等同于多个独立的命令单独执行的效果。 
  • () 表示在当前 shell 中将多个命令作为一个整体执行。需要注意的是,使用 () 括起来的命令在执行前面都不会切换当前工作目录,也就是说命令组合都是在当前工作目录下被执行的,尽管命令中有切换目录的命令。 
  • 命令组合常和命令执行控制结合起来使用。 

示例 4 : 

?


1

2

3

4

[root@Betty ~]# rm ~/workspace/1.txt || (cd ~/workspace/;ls -a;echo "fail")

rm: 无法删除"/root/workspace/1.txt": 没有那个文件或目录

.  ..  CODE_TEST  GIT  mnt  startsrv.log  SVN  test.log  tmp.txt  WGET

fail

在示例 4 中,如果目录 ~/workspace 下不存在文件 1.txt,则执行命令组合。 

===  我是晓松奇谈的分隔线 === 

linux bash shell中,单引号、 双引号,反引号(``)的区别及各种括号的区别

单引号和双引号

首先, 单引号和双引号,都是为了解决中间有空格的问题。 
      因为空格在 linux 中是作为一个很典型的分隔符使用,比如 string1=this is a string,这样执行就会报错。为了避免这个问题,因此就产生了单引号和双引号。区别在于,单引号将剥夺其中的所有字符的特殊含义,而双引号中的 '$'(参数替换)和'`'(命令替换)是例外。所以,两者基本上没有什么区别,除非在内容中遇到了参数替换符$和命令替换符`。 
所以下面的结果: 

?


1

2

3

4

5

6

[root@Betty Shell]# num=3

[root@Betty Shell]# echo '$num'

$num

[root@Betty Shell]# echo "$num"

3

[root@Betty Shell]#

所以,如果需要在双引号里面使用这两种符号本身,则需要使用反斜杠进行转义。 

反引号

      这个东西的用法,和 $() 是一样的。在执行一条命令时,会先将其中的 `xxx` 或 $(xxx) 中的语句当作命令优先执行,再将结果插入到原命令中执行原本的 shell 命令,例如: 

?


1

[root@Betty Shell]# echo `ls`

会先执行 ls 得到 test.txt 等,再替换原命令为: 

?


1

echo test.txt

最后执行结果为 

?


1

test.txt

      所以平时我们遇到的、把一堆命令的执行结果输出到一个变量中的情况,就需要利用这个命令替换符括起来。 
      这里又涉及到了一个问题,虽然不少系统工程师在使用替换功能时,喜欢使用反引号将命令括起来。但是根据 POSIX 规范,要求系统工程师采用的是 $(xxx) 的形式。所以,我们最好还是遵循这个规范,少用 `xxx`,多用 $(xxx) 。 

小括号,中括号,和大括号的区别

先说说小括号和大括号的区别。这两者实际上都是用于表示“命令群组”的概念,也就是 command group 。 

  • () 把 command group 放到 subshell 去执行,也叫做 nested sub-shell。
  • {} 则是在同一个 shell 內完成,也称为 non-named command group。

所以说,如果在 shel l里面执行“函数”,需要用到 {}。 不过,根据实测,test=$(ls -a) 可以正确执行,但是 test=${ls –a} 语法上面是有错误的。 

另外,从网上摘录的两者区别如下: 

  • () 只是对一组命令重新开一个子 shell 进行执行
  • {} 对一串命令在当前shell执行
  • () 和 {} 都是把一串的命令包含在括号内,并且命令之间用分号隔开
  • () 最后一个命令可以不用分号
  • {} 最后一个命令要用分号
  • {} 的第一个命令和左括号之间必须要有一个空格
  • () 里的各命令不必和括号有空格
  • () 和 {} 中括号里面的某个命令的重定向只影响该命令,但括号外的重定向则影响到括号里的所有命令

两个括号 (()),是代表算数扩展,就是对其包括的东西进行标准的算数计算。注意,不能算浮点数,如果需要算浮点数,需要用 bc 做。 
至于中括号 [ ],感觉作用就是用来比较的(这里原作者理解的不好,[ ] 其实是 shell 中的 test 命令 )。比如放在 if 语句里面,while 语句里面,等等。 

时间: 2024-11-13 14:13:14

【转载】书写优雅的shell脚本的相关文章

【SHELL 编程基础第一部分】第一个SHELL脚本HELLOSHELL及一些简单的SHELL基础书写与概念;

本站文章均为 李华明Himi 原创,转载务必在明显处注明:  转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/shell/759.html 本章节分享Shell 学习篇,那么对于Shell 简单介绍下,对于Shell来说,大家可以理解Shell 是一个命令解释器,类似于DOS下的command.com.它接收用户命令(如ls等),然后调用相应的应用程序.另外一点它可以使用用户的缺省凭证和环境执行 shell.传统意义上的shell指的是命令行式的sh

如何书写优雅、漂亮的SQL脚本?

本篇来聊聊如何书写漂亮.整洁.优雅的SQL脚本,下面这些是我个人总结.整理出来的.姑且做个抛砖引玉吧,呵呵,欢迎大家一起来讨论. 我们首先来看看一段创建数据表的脚本(如下所示),你是否觉得有什么不妥或是不足呢?如果是你,你怎样书写呢? 代码Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->CREATE TABLE [dbo].[TableDataDic

运维经验分享(六)-- 深究crontab不能正确执行Shell脚本的问题(二)

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://dgd2010.blog.51cto.com/1539422/1677211 运维经验分享作为一个专题,目前共7篇文章 <运维经验分享(一)-- Linux Shell之ChatterServer服务控制脚本> <运维经验分享(二)-- Linux Shell之ChatterServer服务控制脚本二次优化> <运维经验分享(三)-- 解决Ubuntu下cro

shell脚本学习指南[一](Arnold Robbins &amp; Nelson H.F. Beebe著)_linux shell

第一章略过,下边从第二章开始,大家懂得.ps:这里发生了一件非常当我蛋疼的事情,非常!已经码文章码到第四章了,悲剧的按错浏览器按钮刷新掉,怎么也找不回来之前写的东西了.想死!算了,复习一边吧.以下全文均属自己总结书写,有错误的地方也未必是书中错误(当然也有可能是书中错误,但是我都会亲自操作滴),可能是我写错,请大牛指正. 第二章入门 因为第二遍写,就简单快速的写吧,尽量写清楚.大家都知道的终端命令cd啊 chmod啊 who啊之类的组合在一起加上一些控制语句,变量什么的就成shell编程了,给出

[网摘学习]Shell脚本编程学习入门:Shell编程基础

51cto的这篇文章不错,收藏一下:http://os.51cto.com/art/201109/294521.htm(版权归原作者所有) Shell脚本编程学习入门是本文要介绍的内容,我们可以使用任意一种文字编辑器,比如gedit.kedit.emacs.vi等来编写shell脚本,它必须以如下行开始(必须放在文件的第一行):   #!/bin/sh ... 注意:最好使用"!/bin/bash"而不是"!/bin/sh",如果使用tc shell改为tcsh,其

Linux Shell脚本之通过json判断应用程序内部运行状态

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://dgd2010.blog.51cto.com/1539422/1686475 之前写过一篇<Zabbix监控之Linux命令行/Shell脚本解析json>,文章提到一种"利于Zabbix监控报警的json数据格式",便于运维人员通过API获取应用程序中的运行状态.内部依赖关系等.但有的开发人员没有按照这种格式来,而是采用了下面的这种json数据格式: 成功

Git学习--&amp;gt;如何通过Shell脚本实现 监控Gitlab备份整个过程并且通过邮件通知得到备份结果?

一.背景 Git学习–>如何通过Shell脚本自动定时将Gitlab备份文件复制到远程服务器? http://blog.csdn.net/ouyang_peng/article/details/77334215 git学习--> Gitlab如何进行备份恢复与迁移? http://blog.csdn.net/ouyang_peng/article/details/77070977 Linux学习–>如何通过Shell脚本实现发送邮件通知功能? http://blog.csdn.net/o

Linux学习--&amp;gt;如何通过Shell脚本实现发送邮件通知功能?

1.安装和配置sendmail 不需要注册公网域名和MX记录(不需要架设公网邮件服务器),通过Linux系统自带的mail命令即可对公网邮箱发送邮件.不过mail命令是依赖sendmail的,所以我们需要先检查安装和配置sendmail. 一般系统都自带sendmail,但是只能给内网的邮箱发邮件.如果想给公网的邮箱发邮件(比如qq邮箱)就需要配置sendmail. 这里记录sendmail的安装启动配置,各取所需. 尝试使用mail命令发送一封邮件. root@ubuntu4146:/data

Git学习--&amp;gt;如何通过Shell脚本自动定时将Gitlab备份文件复制到远程服务器?

一.背景 在我之前的博客 git学习--> Gitlab如何进行备份恢复与迁移? (地址:http://blog.csdn.net/ouyang_peng/article/details/77070977) 里面已经写清楚了如何使用Gitlab自动备份功能. 但是之前的备份功能只是备份到Gitlab服务运行的那台服务器上,如果哪一天那台服务器的磁盘损坏了的话,数据无法取出,那么对于公司来说是一匹无法想象的损失,因为 代码是公司的重要资产,需要以防万一. 代码是公司的重要资产,需要以防万一. 代码