Skip to content

shell脚本

关于引号

单引号:

可以说是所见即所得:即将单引号内的内容原样输出,或者描述为单引号里面看见的是什么就会输出什么。

双引号:

把双引号内的内容输出出来;如果内容中有命令,变量等,会先把变量,命令解析出结果,然后在输出最终内容来。

双引号内命令或变量的写法为命令或变量或$(命令或变量)。

无引号:

把内容输出出来,可能不会讲含有空格的字符串视为一个整体输出;

如果内容中有命令、变量等,会先把变量、命令解析结果,然后在输出最终内容来;

如果字符串中带有空格等特殊字符,则不能完整的输出,需要改加双引号,一般连续的字符串,数字,路径等可以用,不过最好用双引号替代之

sh文件获取当前绝对路径

获取sh文件所在的绝对路径

shell
filepath=$(cd "$(dirname "$0")"; pwd)

sh根据端口查进程

下面是一个sh示例,需要输入一个参数,即端口。可能会有重复打印

shell
#!/bin/bash

# 检查是否提供了端口号作为参数
if [ -z "$1" ]; then
    echo "请提供端口号作为参数!"
    exit 1
fi

# 设置端口号变量
PORT=$1

# 使用 netstat 命令获取端口信息
# 注意: netstat -tulnp 可以获取到 PID,而 PID 可以用于进一步查找程序名称
# 过滤输出只保留感兴趣的行
netstat -tulnp | grep ":$PORT" | awk '{print $7}' | cut -d'/' -f1 | while read -r pid; do
    echo "Process ID: $pid"
    # 使用 ps 命令根据 PID 查找程序名称
    ps -p $pid -o pid,command,cmd | while read -r line; do
        echo "$line"
    done
done

if判断

if的基本语法

shell
if [ command ];then
   符合该条件执行的语句
elif [ command ];then
   符合该条件执行的语句
else
   符合该条件执行的语句
fi

文件/文件夹判断

shell
[ -b FILE ] 如果 FILE 存在且是一个块特殊文件则为真。
[ -c FILE ] 如果 FILE 存在且是一个字特殊文件则为真。
[ -d DIR ] 如果 FILE 存在且是一个目录则为真。
[ -e FILE ] 如果 FILE 存在则为真。
[ -f FILE ] 如果 FILE 存在且是一个普通文件则为真。
[ -g FILE ] 如果 FILE 存在且已经设置了SGID则为真。
[ -k FILE ] 如果 FILE 存在且已经设置了粘制位则为真。
[ -p FILE ] 如果 FILE 存在且是一个名字管道(F如果O)则为真。
[ -r FILE ] 如果 FILE 存在且是可读的则为真。
[ -s FILE ] 如果 FILE 存在且大小不为0则为真。
[ -t FD ] 如果文件描述符 FD 打开且指向一个终端则为真。
[ -u FILE ] 如果 FILE 存在且设置了SUID (set user ID)则为真。
[ -w FILE ] 如果 FILE存在且是可写的则为真。
[ -x FILE ] 如果 FILE 存在且是可执行的则为真。
[ -O FILE ] 如果 FILE 存在且属有效用户ID则为真。
[ -G FILE ] 如果 FILE 存在且属有效用户组则为真。
[ -L FILE ] 如果 FILE 存在且是一个符号连接则为真。
[ -N FILE ] 如果 FILE 存在 and has been mod如果ied since it was last read则为真。
[ -S FILE ] 如果 FILE 存在且是一个套接字则为真。
[ FILE1 -nt FILE2 ] 如果 FILE1 has been changed more recently than FILE2, or 如果 FILE1 exists and FILE2 does not则为真。
[ FILE1 -ot FILE2 ] 如果 FILE1 比 FILE2 要老, 或者 FILE2 存在且 FILE1 不存在则为真。
[ FILE1 -ef FILE2 ] 如果 FILE1 和 FILE2 指向相同的设备和节点号则为真。

字符串判断

shell
[ -z STRING ] 如果STRING的长度为零则为真 ,即判断是否为空,空即是真;
[ -n STRING ] 如果STRING的长度非零则为真 ,即判断是否为非空,非空即是真;
[ STRING1 = STRING2 ] 如果两个字符串相同则为真 ;
[ STRING1 != STRING2 ] 如果字符串不相同则为真 ;
[ STRING1 ]  如果字符串不为空则为真,与-n类似

数值判断

shell
INT1 -eq INT2           INT1和INT2两数相等为真 ,=
INT1 -ne INT2           INT1和INT2两数不等为真 ,<>
INT1 -gt INT2            INT1大于INT1为真 ,>
INT1 -ge INT2           INT1大于等于INT2为真,>=
INT1 -lt INT2             INT1小于INT2为真 ,<</div>
INT1 -le INT2             INT1小于等于INT2为真,<=

逻辑判断

shell
-a
-o
!

exp1: 如果a>b且a<c
if (( a > b )) && (( a < c ))
或者
if [[ $a > $b ]] && [[ $a < $c ]]
或者
if [ $a -gt $b -a $a -lt $c ]

exp2:如果a>b或a<c
if (( a > b )) || (( a < c ))
或者
if [[ $a > $b ]] || [[ $a < $c ]]
或者
if [ $a -gt $b -o $a -lt $c ]
 
"||""&&"在SHELL里可以用,也就是第一个写成if [ a>b && a<c ]

[ ]与[[ ]]

在Shell脚本中,单中括号[]和双中括号[[ ]]是两种不同的条件测试结构,它们在功能和使用场景上存在显著的区别。

‌单中括号[]‌: 单中括号是传统的POSIX风格语法,用于基本的条件测试。 它支持较少的操作符,主要处理简单的条件判断,如字符串比较和文件测试。 在单中括号内,变量需要进行引用以避免单词分割,即如果变量值包含空白符,需要用引号将变量括起来。 单中括号不支持正则表达式匹配和逻辑运算符。

‌双中括号[[ ]]‌: 双中括号是Bash特有的扩展,提供了更强大的功能和更灵活的条件判断。 它支持更复杂的表达式,包括正则表达式匹配、逻辑运算符、更丰富的字符串比较等。 在双中括号内,变量不需要引用,也不会导致错误的变量扩展。 双中括号允许使用通配符进行模式匹配,支持使用==和!=进行字符串比较,而单中括号只能使用=进行字符串比较。 ‌使用场景‌:

单中括号适合基本的条件判断,如检查文件是否存在、比较两个字符串是否相等等。 双中括号适合需要更复杂逻辑判断的场景,如使用正则表达式匹配字符串模式、进行逻辑与或运算等。 总的来说,双中括号提供了更多的功能和灵活性,尤其是在处理复杂的条件判断和字符串处理时。而单中括号则更适合简单的条件测试和基本的字符串比较‌

加不加引号

-z 判断 变量的值,是否为空; zero = 0

  • 变量的值,为空,返回0,为true
  • 变量的值,非空,返回1,为false -n 判断变量的值,是否为空 name = 名字
  • 变量的值,为空,返回1,为false
  • 变量的值,非空,返回0,为true pid="123"

[ -z "$pid" ] 单对中括号变量必须要加双引号 [[ -z $pid ]] 双对括号,变量不用加双引号 [ -n "$pid" ] 单对中括号,变量必须要加双引号 [[ -z $pid ]] 双对中括号,变量不用加双引号

[[ ]] 双对中括号,是不能使用 -a 或者 -o的参数进行比较的

&& 并且 || 或 -a 并且 -o 或者 [[ ]] 条件判断 && 并且 || 或
[[ 5 -lt 3 || 3 -gt 6 ]] 一个条件,满足,就成立 或者的关系 [[ 5 -lt 3 || 3 -gt 6 ]] 一个条件满足,就成立 或者的关系 [[ 5 -lt 3 ]] || [[3 -gt 6 ]] [[ 5 -lt 3 ]] || [[3 -gt 6 ]] 写在外面也可以

&& 必须两个条件同时满足,和上述一样,这里想说明的问题的是:

[[ 5 -lt 3]] -o [[ 3 -gt 6 ]] [[ 5 -lt 3 -o 3 -gt 6 ]] [[ 5 -lt 3 -a 3 -gt 6 ]] [[ 5 -lt 3 -a 3 -gt 6 ]]

-a 和 -o就不成立了,是因为,[[]] 双对中括号,不能使用 -o和 -a的参数

[ ] 可以使用 -a -o的参数,但是必须在 [ ] 中括号内

[ 5 -lt 3 -o 3 -gt 2 ] 或者条件成立 [5 -lt 3 ] -o [ 3 -gt 2] 或者条件, 这个不成立,因为必须在中括号内判断

如果想在中括号外判断两个条件,必须用&& 和 || 比较 [5 -lt 3 ] || [ 3 -gt 2] [5 -gt 3 ] && [ 3 -gt 2] 成立 相对的,|| 和 && 不能在中括号内使用,只能在中括号外使用

当判断某个变量的值是否满足正则表达式的时候,必须使用[[ ]] 双对中括号

特殊变量

名称说明
$0脚本名称
$1-9脚本执行时的参数1到参数9
$?脚本的返回值
$#脚本执行时,输入的参数的个数
$@输入的参数的具体内容(将输入的参数作为一个多个对象,即是所有参数的一个列表
$*输入的参数的具体内容(将输入的参数作为一个单词)

$@与$*的区别:

$@与$*都可以使用一个变量来来表示所有的参数内容,但这两个变量之间有一些不同之处。

$@:将输入的参数作为一个列表对象

$*:将输入的参数作为一个单词

shell
echo "脚本的名字是:"$0
n=1
echo "使用\$@的参数列表为:"$@
for temstr in "$@"
do
        echo "第$n个参数是:" $temstr
        let n+=1
done

n=1
echo "使用\$*的参数列表为:"$*
for temstr in "$*"
do
         echo "第$n个参数是:" $temstr
         let n+=1
done

执行以上脚本,设为test.sh,结果应为

shell
./test.sh 1 2 3 4
脚本的名字是:./test.sh
使用$@的参数列表为:1 2 3 4
第1个参数是: 1
第2个参数是: 2
第3个参数是: 3
第4个参数是: 4
使用$*的参数列表为:1 2 3 4
第1个参数是: 1 2 3 4

磁盘挂载

挂载windows共享目录

shell
mount -t cifs -o username=administrator,password=xxx //172.17.0.68/backup/WIKI /mnt/WIKI

解除挂载

shell
umount /mnt/WIKI

定时任务

每月最后一天执行

shell
30 23 28-31 * * [ $(date -d tomorrow +%d) -eq 1 ] && bash /path/to/your/script.sh

上面的可能不太稳妥,可能由于版本原因不兼容,下面的方案更稳定。判断最后一天写在脚本中。 不妨创建一个last_day_script.sh文件,内容如下:

shell
if [ $(date -d tomorrow +%d) -eq 1 ]; then
    /path/to/your/script.sh
else
    echo 'not last day'
fi

然后在crontab中添加如下任务:

shell
30 23 28-31 * * bash /path/to/your/last_day_script.sh

CPU信息

总核数 = 物理CPU个数 X 每颗物理CPU的核数 总逻辑CPU数 = 物理CPU个数 X 每颗物理CPU的核数 X 超线程数

查看完整信息

shell
cat /proc/cpuinfo

查看物理CPU个数

shell
cat /proc/cpuinfo| grep "physical id"| sort| uniq| wc -l

查看每个物理CPU中core的个数(即核数)

shell
cat /proc/cpuinfo| grep "cpu cores"| uniq

查看逻辑CPU的个数

shell
cat /proc/cpuinfo| grep "processor"| wc -l

查看CPU信息(型号)

shell
cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq -c

内存信息

查看内存信息

shell
cat /proc/meminfo

查看机器型号(机器硬件型号)

shell
dmidecode | grep "Product Name"
# or 全部
dmidecode

系统信息

如何查看Linux 内核

shell
uname -a
# or
cat /proc/version

如何查看linux 系统版本

shell
# centos实测可用
cat /etc/redhat-release

# Ubuntu实测可用
lsb_release -a
cat  /etc/issue