一、shell脚本
当命令或程序语句不在命令行下执行,而是通过一个程序文件来执行时,该程序就被称为shell脚本。
二、清除/var/log下messages日志文件的简单命令脚本
#!/bin/bash
# 清除日志脚本
LOG_DIR=/var/log
ROOT_UID=0 #<==$UID为0的用户,即root用户
if [ "$UID" -ne "$ROOT_UID" ]
then
echo "MUST be root to run this script."
exit 1
fi
cd $LOG_DIR || {
echo "Cannot change to necessary directory"
exit 1
}
cat /dev/null>messages && {
echo "Logs cleaned up."
exit 0
}
echo "Logs cleaned up fail."
exit 1
上面的脚本设计成了如下几关:
第一关:必须是root才能执行脚本,否则会给出友好提示并终止脚本运行
第二关:成功切换目录(cd /var/log),否则给出友好提示并终止脚本运行
第三关:清理日志(cat /dev/null>messages),若清理成功,则给出正确提示。
第四关:通过或失败,分别给出相应的提示(echo输出)
三、shell脚本语言是弱类型语言(无需定义变量的类型即可使用),在UNIX/LINUX中主要有两大类shell:Bourne shell 和 C shell
(1)查看系统的shell支持情况。cat/etc/shells(2)查看系统默认的shell。方法一:echocat/etc/shells(2)查看系统默认的shell。方法一:echoSHELL
/bin/bash
方法二:grep root /etc/passwd
root:x:0:0:root:/root:/bin/bash
四、shell脚本的建立
(1)脚本开头。一个规范的shell脚本会在第一行指出由哪个程序(解释器)来执行脚本中的内容,这一行内容在Linux bash的编程一般为:#!/bin/bash
(2)查看系统的bash版本的命令。bash –version
(3)检测系统是否存在漏洞的方法。env x=’() { :;}; echo be careful’ bash -c “echo this is a test”
如果出现:this is a test 则没有漏洞。否则,则需尽快升级bash了。
(4)下面是Linux中常用的脚本开头的写法。
#!/bin/bash
#!/bin/sh
#!/usr/bin/awk
#!/bin/sed
#!/usr/bin/tcl
#!/usr/bin/expect #<==expect解决交互式的语言开头解释器
#!/usr/bin/perl #<==Perl语言解释器
#!/usr/bin/env python #<==python语言解释器
如果在脚本开头的第一行不指定解释器,那么就要用对应的解释器来执行脚本。这样才能确保脚本正确执行。例如:
如果是shell脚本,就用bash test.sh执行test.sh
如果是Python脚本,就用python test.py执行test.py
如果是expect脚本,就用expect test.exp执行test.exp
(5)脚本注释
在shell脚本中,跟在#后面的内容表示注释,用来对脚本进行注释说明。
五、shell脚本的执行通常采用以下几种方式:
(1)bash script-name 或 sh script-name:这是当脚本文件本身没有可执行权限(即文件权限属性x位为-号)时常用的方法,或者脚本文件开头没有指定解释器时需要使用的方法。
(2)path/script-name 或 ./script-name :指在当前路径下执行脚本(脚本需要有执行权限),然后就直接应用了。(可以使用chmod命令来变更文件或目录的权限。权限的表示法如下:
u User,即文件或目录的拥有者;
g Group,即文件或目录的所属群组;
o Other,除了文件或目录拥有者或所属群组之外,其他用户皆属于这个范围;
a All,即全部的用户,包含拥有者,所属群组以及其他用户;
r 读取权限,数字代号为“4”;
w 写入权限,数字代号为“2”;
x 执行或切换权限,数字代号为“1”;
- 不具任何权限,数字代号为“0”;
s 特殊功能说明:变更文件或目录的权限。)
(3)source script-name 或 . script-name :这种方法通常是使用source或“.”读入或加载指定的shell脚本文件,然后依次执行指定的shell脚本文件中的所有语句。这些语句将在当前父shell脚本father.sh进程中运行(其他几种模式都会启动新的进程执行子脚本)。因此,使用source或“.”可以将son.sh自身脚本中的变量值或函数等的返回值传递到当前父shell脚本father.sh中使用。
(4)shtestsource.sh
$ cat testsource.sh
userdir=pwd
sh testsource.sh #<==采用sh命令执行脚本sh testsource.sh #<==采用sh命令执行脚本 echo $userdir
#<==此处为空并没有出现当前路径/home/tianhao/shellscript
通过sh或bash命令执行过的脚本,若在脚本结束之后在当前shell窗口中查看usedir变量的值,会发现值是空的。如果以同样的步骤改用source或“.”执行,然后看userdir变量的值。
sourcetestsource.shsourcetestsource.sh echo userdir/home/tianhao/shellscript结论:通过source或“.”加载执行过的脚本,由于是在当前shell中执行脚本,因此在脚本结束之后,脚本中的变量(包括函数)值在当前shell中仍然存在,而sh和bash执行脚本都会启动新的子shell执行,执行完后退回到父shell。因此,变量(包括函数)值等无法保留。在进行shell脚本开发时,如果脚本中有引用或执行其他脚本的内容或配置文件的需求时,最好用“.”或source先加载该脚本或配置文件,处理完之后,再将他们加载到脚本的下面,就可以调用source加载的脚本及配置文件中的变量及函数等内容了。八、采用第四种方法来实践:userdir/home/tianhao/shellscript结论:通过source或“.”加载执行过的脚本,由于是在当前shell中执行脚本,因此在脚本结束之后,脚本中的变量(包括函数)值在当前shell中仍然存在,而sh和bash执行脚本都会启动新的子shell执行,执行完后退回到父shell。因此,变量(包括函数)值等无法保留。在进行shell脚本开发时,如果脚本中有引用或执行其他脚本的内容或配置文件的需求时,最好用“.”或source先加载该脚本或配置文件,处理完之后,再将他们加载到脚本的下面,就可以调用source加载的脚本及配置文件中的变量及函数等内容了。八、采用第四种方法来实践:cat test.sh
!#/bin/bash
echo “I am a good boy”
$ cat test.sh|bash #<==这种方法在命令行拼接字符串命令后,需要执行时就会用到
I am a good boy
九、shell脚本开发的基本规范及习惯。
基本规范:
(1)shell脚本的第一行是指定脚本解释器,通常为:
!#/bin/bash
(2)shell脚本的开头会加版本、版权等信息:
# Date: 16:29 2017-12-30
#Author: Created by tianhao
#Description: This is ...
#version: 1.1
可修改”~/.vimrc”配置文件vim编辑文件是自动加上以上信息的功能。
(3)在shell脚本中尽量不用中文,注释也是如此。
如果非要加中文,请根据自身的客户端对系统进行字符集的调整,如:export LANG=”zh_CN.UTF-8”,并在脚本中,重新定义字符集设置,和系统保持一致。
(4)shell脚本的命名应以.sh为扩展名。
(5)shell脚本应存放在固定的路径下。例如: /server/scripts
习惯:
(1)成对的符号应尽量一次性写出来,然后退格在符号里增加内容,以防止遗漏。
(2)中括号([])两端至少要有1个空格,因此,键入中括号时即可留出空格([ ]),然后再退格键入中间的内容,并确保两端都至少有一个空格。双中括号的写法也是如此。
(3)对于流程控制语句,应一次性将格式写完,再添加内容。
(4)注意代码缩进。
(5)对于常规变量的字符串定义变量值应加双引号,并且等号前后不能有空格,需要强引用的(指所见即所得的字符引用),则用单引号(’’),若是命令的引用,则用反引号(``)。
(6)脚本中的单引号、双引号及反引号必须为英文状态下的符号,其实所有的Linux字符及符号都应该是英文状态下的符号。