Shell脚本

基础知识

条件判断

  • 文件类型判断
测试选项 作用
-b 文件 判断该文件是否存在,并且是否为块设备文件(是块设备文件为真)
-c 文件 判断该文件是否存在,并且是否为字符设备文件(是字符设备文件为真)
-d 文件 判断该文件是否存在,并且是否为目录(是目录为真)
-e 文件 判断该文件是否存在(存在为真)
-f 文件 判断该文件是否存在,并且是否为普通文件(是普通文件为真)
-L 文件 判断该文件是否存在,并且是否为符号链接文件(是符号链接文件为真)
-p 文件 判断该文件是否存在,并且是否为管道文件(是管道文件为真)
-s 文件 判断该文件是否存在,并且是否为非空(非空为真)
-S 文件 判断该文件是否存在,并且是否为套接字文件(是套接字文件为真)
  • 文件权限判断
测试选项 作用
-r 文件 判断该文件是否存在,并且是否该文件拥有读权限(有读权限为真)
-w 文件 判断该文件是否存在,并且是否该文件拥有写权限(有写权限为真)
-x 文件 判断该文件是否存在,并且是否该文件拥有执行权限(有执行权限为真)
-u 文件 判断该文件是否存在,并且是否该文件拥有SUID权限(有SUID权限为真)
-g 文件 判断该文件是否存在,并且是否该文件拥有SGID权限(有SGID权限为真)
-h 文件 判断该文件是否存在,并且是否该文件拥有SBit权限(有SBit权限为真)
  • 文件比较
测试选项 作用
A -nt B 判断A的修改时间是否比B的新(如果新则为真)
A -ot B 判断A的修改时间是否比B的旧(如果旧则为真)
A -ef B 判断A和B的inode号是否一致,可以理解为两个文件是否为同一个文件。这个判断用于判断硬链接是很好的方法
  • 整数比较
测试选项 作用
A -eq B 判断A和B是否相等(相等为真)
A -ne B 判断A和B是否不相等(不相等为真)
A -gt B 判断A是否大于B(大于为真)
A -lt B 判断A是否小于B(小于为真)
A -ge B 判断A是否大于等于B(大于等于为真)
A -le B 判断A是否小于等于B(小于等于为真)
  • 字符串比较
测试选项 作用
-z 字符串 判断字符串是否为空(为空返回真)
-n 字符串 判断字符串是否非空(非空返回真)
A == B 判断A和B是否相等(相等返回真)
A != B 判断A和B是否不相等(不相等返回真)
  • 多重条件判断
测试选项 作用
A -a B 逻辑与,A和B都成立,最终的结果才为真
[ A ] and [B] 逻辑与,A和B都成立,最终的结果才为真
A -o B 逻辑或,A或B有一个成立,最终的结果就为真
[ A ] or [B] 逻辑或,A或B有一个成立,最终的结果就为真
! A 逻辑非,是原始的判断式取反

基本语法

  • if语法
### 方式一
if [ 条件 ]; then
    命令
fi

if [ 条件 ] && [ 条件 ]; then
    命令
fi

if [ 条件 ]
    then
        命令
fi

### 方式二
if [ 条件 ]; then
    命令
else
    命令
fi

if [ 条件 ]
    then
        命令
    else
        命令
fi

### 方式三
if [ 条件 ]; then
    命令
elif [ 条件 ]; then
    命令
else
    命令
fi

if [ 条件 ]
    then
        命令
elif [ 条件 ]
    then
        命令
else
    命令
fi
  • case语法
case $VAL in
    "A")
    命令
    ;;
    "B")
    命令
    ;;
    *)
    命令
    ;;
esac
  • for语法
for VAL in $VAL;do
    命令
done

for VAL in $VAL
    do
        命令
    done
  • while语法
while [ 条件 ];do
    命令
done

while [ 条件 ]
    do
        命令
    done
  • until语法
until [ 条件 ];do
    命令
done

until [ 条件 ]
    do
        命令
    done

语法样例


### case样例
#!/bin/sh

for VAL in 1 2 3; do
  echo "VAL is $VAL"
  case $VAL in
    1)
    echo "1"
    ;;
    2)
    echo "2"
    ;;
    *)
    echo "*"
    ;;
  esac
done

### for样例
#!/bin/sh

for VAL in 3 4; do
  echo "A VAL is $VAL"
done

for VAL in 5 6
  do
    echo "A VAL is $VAL"
  done

### while样例
#!/bin/sh

VAL=7

while [ $VAL -gt 5 ]; do
  echo "A VAL is $VAL"
  VAL=$[VAL - 1]
done

while [ $VAL -gt 3 ]
  do
    echo "B VAL is $VAL"
    VAL=$[VAL - 1]
  done


### until样例
#!/bin/sh

VAL=7

until [ $VAL -lt 5 ]; do
  echo "A VAL is $VAL"
  VAL=$[VAL - 1]
done

until [ $VAL -lt 3 ]
  do
    echo "B VAL is $VAL"
    VAL=$[VAL - 1]
  done

字符串高级操作

样例变量VAL=http://news.163.com/index.html

  • #号截取,删除左边字符,保留右边字符(非贪婪匹配)
### *//表示从左边开始删除第一个//及其左边的字符(*),结果为:news.163.com/index.html
echo ${VAL#*//}
  • ##截取,删除左边字符,保留右边字符(贪婪匹配)
### */表示从左边开始删除最后一个/(最右边)及其左边的字符(*),结果为:index.html
echo ${VAL##*/}
  • %号截取,删除右边字符,保留左边字符(非贪婪匹配)
### /*表示从右边开始,删除第一个/及其右边的字符(*),结果为:http://news.163.com
echo ${VAL%/*}
  • %%号截取,删除右边字符,保留左边字符(贪婪匹配)
### /*表示从右边开始,删除最后一个/(最左边)及其右边的字符(*),结果为:http:
echo ${VAL%%/*}
  • 指定位置截取,从左边的第N个字符开始的M个字符
### 0表示从左边的第1个字符开始的4个字符,结果为:http
echo ${VAL:0:4}
  • 指定位置截取,从左边的第N个字符开始直到结束
### 7表示从左边的第8个字符开始直到结束,结果为:news.163.com/index.html
echo ${VAL:7}
  • 指定位置截取,从右边的第N个字符开始的M个字符
### 0-10表示从右边的第10个字符开始的5个字符,结果为:index
echo ${VAL:0-10:5}
  • 指定位置截取,从右边的第N个字符开始直到结束
### 0-10表示从右边的第10个字符开始直到结束,结果为:index.html
echo ${VAL:0-10}

在命令行中编写shell

### 如果/etc/default/grub文件中不存在匹配内容则添加
# if grep -q 'net.ifnames=0 biosdevname=0' /etc/default/grub; then echo "nothing to do"; else sed -e 's/GRUB_CMDLINE_LINUX="[^"]*/& net.ifnames=0 biosdevname=0/g' /etc/default/grub; fi

### 使用xargs将前面命令的执行结果转换为当前命令的变量(不过变量前面会有一个空格)
# ip addr show ens4 | grep link/ether | awk '{print $2}' | xargs echo "ATTR{address}==$1"
# ip addr show ens4 | grep link/ether | awk '{print $2}' | xargs echo "ATTR{address}==$1"
ATTR{address}== 52:54:00:c5:04:e1
### 使用下面这种方式就不会存在空格
# ip addr show ens4 | grep link/ether | echo "ATTR{address}==`awk '{print $2}'`"
ATTR{address}==52:54:00:c5:04:e1
  • 批量拷贝特定文件
### 查找test目录下的txt文件,并复制到当前目录
# find test/ -name *.txt | xargs -i cp {} ./

在文件中编写shell

变量的定义

  • 字符串变量
# =号两边不能有空格
var="string"
  • 命令执行结果
var=`ls`

条件判断

#!/bin/sh

# cond两边要留一个空格,todo部分前面需要一个tab,不能是空格
if [ cond ]; then
    # todo
else
    # todo
fi

样例一

#!/bin/sh
# 检测目录是否存在
if [ ! -d "$HOME/test" ]; then
    mkdir "$HOME/test"
fi
# 检测文件是否存在
if [ ! -f "$HOME/test/test.txt" ]; then
    touch "$HOME/test/test.txt"
fi
# 检测字符串是否为空
if [ -z "$VAL" ]; then
    echo "Empty string"
fi

样例二

#!/bin/sh

# 添加内容到文件
var="127.0.0.1"
if [ ! -f "/etc/rsyslog.conf" ]; then
    sudo sh -c "echo 'local4.* @'${var} >> /etc/rsyslog.conf"
    echo 'local4.* @'${var} | sudo tee -a /etc/rsyslog.conf
fi

样例三

#!/bin/sh

var="$1"

if [ "$var" = "0" ]; then
    echo "Login"
elif  [ "$var" = "1" ]; then
    echo "Logout"
else
    echo "Exit"
fi

实际应用

  • 逐行读取文件 & 拼接字符串
#!/bin/sh

### 由于使用for来读入文件里的行时,会自动把空格和换行符作为一样分隔符,如果行里有空格的时候,输出的结果会很乱,所以只适用于行连续不能有空格或者换行符的文件
for line in $(grep CLASSPATH /usr/lib/systemd/system/zookeeper.service.d/classpath.conf)
do
    cmd="${cmd} ${line##*=}"
done

### 使用while来读入文件里的行时,会整行读入,不会关注行的内容(空格..),所以比for读文件有更好的适用性,推荐使用while循环读取文件
while read line
do
    cmd="${cmd} ${line#*=}"
done < /etc/sysconfig/zookeeper
  • 将命令结果保存到变量
#!/bin/sh

A_VAL=$(ls)

B_VAL=`ls`
posted @ 2017-10-14 09:52  银魔术师  阅读(265)  评论(0编辑  收藏  举报