土豆排骨饭 发表于 2024-2-21 01:45:17

shell脚本


[*]shell
执行shell脚本的方式
方式一:bash
bash test.sh
 
方式二:./
./test.sh
 
方式三: 使用脚本完整路径
/root/test.sh
 
方式四:使用source,以当前默认 Shell 解释器执行
source test.sh
常用系统变量
在命令行提示符直接执行 env、set 查看系统或环境变量。
系统变量 作用
$HOME 当前用户家目录
$SHELL 默认 Shell
$IFS 内部字段分隔符
$LANG 默认语言
$PATH 默认可执行程序路径
$PWD 当前目录
$UID 当前用户 ID
$USER 当前用户
$HISTSIZE 历史命令大小,可通过 HISTTIMEFORMAT 变量设置命令执行时间
$RANDOM 随机生成一个 0 至 32767 的整数
$BASHPID 当前bash的PID号
$HOSTNAME 主机名
ps axjf 输出的第一列是 PPID(父进程 ID),第二列是 PID(子进程 ID)
位置变量
位置变量指的是函数或脚本后跟的第 n 个参数。
$1-n,需要注意的是从第 10 个开始要用花括号调用,例如${10}
shift 可对位置变量控制,例如:
#!/bin/bash
echo "1: $1"
shift
echo "2: $2"
shift
echo "3: $3"
# bash test.sh a b c
1: a
2: b
3: c
 
每执行一次 shift 命令,位置变量个数就会减一,而变量值则提前一位。shift n,可设置向前移动n位。
特殊变量
变量名 作用
$0 脚本自身名字
$1 脚本后跟的第一个位置参数,如果个数超过10,需要使用{}
$* 显示脚本后跟的所有参数,所有的位置参数被看做一个字符串
$@ 显示脚本后跟的所有参数,每个位置参数被看做独立的字符串
$# 显示参数的个数
$? 显示上条命令的执行结果,0为成功,非0失败,范围0-255
$$ 当前进程 PID
$! 上一条运行后台进程的 PID
变量引用
赋值运算符 示例
= 变量赋值
+= 两个变量相加
自定义变量与引用
# VAR=123
# echo $VAR
123
# VAR+=666
# echo $VAR
123666
Shell 中所有变量引用使用$符,后跟变量名。
有时个别特殊字符会影响正常引用,那么需要使用${VAR},例如:
# VAR=123
# echo $VAR
123
# echo $VAR_
# echo ${VAR}
123
还有时候变量名与其他字符串紧碍着,也会误认为是整个变量:
# echo $VAR666
# echo ${VAR}666
123666
将命令结果作为变量值
# VAR=`date`
# echo $VAR
Mon Oct 25 18:05:14 CST 2021
#
# VAR=$(date)
# echo $VAR
Mon Oct 25 18:05:27 CST 2021
这里的反撇号等效于$(),都是用于执行 Shell 命令。
双引号和单引号
在变量赋值时,如果值有空格,Shell 会把空格后面的字符串解释为命令:
# VAR=2 3 4
bash: 3: command not found
# VAR="2 3 4"
# echo $VAR
2 3 4
# VAR='3 3 4'
# echo $VAR
3 3 4
看不出什么区别,再举个说明:
# N=2
# VAR="1 $N"
# echo $VAR
1 2
# VAR='1 $N'
# echo $VAR
1 $N
单引号是告诉 Shell 忽略特殊字符,而双引号则解释特殊符号原有的意义,比如$、!。
单引号:所见即所得
反引号:先执行里面的命令
双引号:会对具有特殊意义的字符做解析
shell注释
Shell 注释也很简单,只要在每行前面加个#号,即表示 Shell 忽略解释。
变量赋值总结
变量赋值语句
向变量中写入内容。vimvv

#read
-p 交互的时候提示信息。
-t 超过这个时间没有操作,则自动退出.
-s 不显示用户的输入.记录密码才用.
#基本用法
read -p "请输入密码:" pass
请输入密码:*******'''
echo $pass
*******'''
read -p "请输入密码:" pass
请输入密码:zhongfei123
echo $pass
zhongfei123
 
不显示用户的输入.
# read -s -p "请输入密码:" pass
请输入密码:#
# echo $pass
zhong
 
同时向2个变量赋值。
read -p "请输入2个数字num1 num2:" num1 num2
请输入2个数字num1 num2:zhong fei
echo $num1 $num2
zhong fei
案例:用户输入1个字符串,然后进行显示
# cat 09.fake_guess.sh
#!/bin/bash
read -s -p "请偷偷的输入你心中所想的内容:" guess
echo ""
sleep 1
echo "我与你心连心,心有灵犀一点通"
sleep 2
echo "我似乎知道你想的内容了"
sleep 3
echo "是不是这个: $guess"
字符串处理
获取字符串长度
# VAR='hello world!'
# echo $VAR
hello world!
# echo ${#VAR}
12
字符串切片
格式:
${parameter:offset}
${parameter:offset:length}
 
截取 hello 字符串:
# VAR='hello world!'
# echo ${VAR:0:5}
hello
截取 wo 字符:
# echo ${VAR:6:2}
wo
截取 world!字符串:
# echo ${VAR:5}
world!
截取最后一个字符:
# echo ${VAR:(-1)}
!
截取最后二个字符:
# echo ${VAR:(-2)}
d!
截取从倒数第 3 个字符后的 2 个字符:
# echo ${VAR:(-3):2}
ld
替换字符串
格式:${parameter/pattern/string}
${变量名/要替换谁/替换成什么}
 
# VAR='hello world world!'
将第一个 world 字符串替换为 WORLD:
# echo ${VAR/world/WORLD}
hello WORLD world!
将全部 world 字符串替换为 WORLD:
# echo ${VAR//world/WORLD}
hello WORLD WORLD!
替换正则匹配为空:
# VAR=123abc
# echo ${VAR//[^0-9]/}
123
# echo ${VAR///}
abc
pattern 前面开头一个正斜杠为只匹配第一个字符串,两个正斜杠为匹配所有字符。
字符串截取
格式:
${parameter#word} #从变量左边开始删除,按照最短匹配删除
${parameter##word} #从变量左边开始删除,按照最长匹配删除
${parameter%word} # 从变量右边开始删除,按照最短匹配删除
${parameter%%word} #从变量右边开始删除,按照最长匹配删除
# 去掉左边,最短匹配模式,##最长匹配模式。
% 去掉右边,最短匹配模式,%%最长匹配模式。
 
# URL="http://www.baidu.com/baike/user.html"
以//为分隔符截取右边字符串:
# echo ${URL#*//}
www.baidu.com/baike/user.html
以/为分隔符截取右边字符串:
# echo ${URL##*/}
user.html
以//为分隔符截取左边字符串:
# echo ${URL%%//*}
http:
以/为分隔符截取左边字符串:
# echo ${URL%/*}
http://www.baidu.com/baike
以.为分隔符截取左边:
# echo ${URL%.*}
http://www.baidu.com/baike/user
以.为分隔符截取右边:
# echo ${URL##*.}
html
变量状态赋值
${VAR:-string} 如果 VAR 变量为空则返回 string
${VAR:+string} 如果 VAR 变量不为空则返回 string
${VAR:=string} 如果 VAR 变量为空则重新赋值 VAR 变量值为 string
${VAR:?string} 如果 VAR 变量为空则将 string 输出到 stderr
 
例:如果变量不为空就返回 hello world!: # VAR="hello"
# echo ${VAR:+'hello world!'}
hello world!
如果变量为空就重新赋值:
# VAR=
# echo ${VAR:=hello}
hello
# echo $VAR
hello
如果变量为空就将信息输出 stderr: # VAR=
# echo ${VAR:?value is null}
-bash: VAR: value is null
字符串颜色
https://blog.csdn.net/yetugeng/article/details/89978787
Shell 表达式与运算符
整数比较符
比较符 描述 示例
-eq,equal 等于 [ 1 -eq 1 ]为 true
-ne,not equal 不等于 [ 1 -ne 1 ]为 false
-gt,greater than 大于[ 2 -gt 1 ]为 true
-lt,lesser than 小于 [ 2 -lt 1 ]为 false
-ge,greater or equal 大于或等于 [ 2 -ge 1 ]为 true
-le,lesser or equal 小于或等于 [ 2 -le 1 ]为 false
#示例:测试一下 10 是否大于 10 以及 10 是否等于 10(通过输出的返回值内容来判断):
# [ 10 -gt 10 ]
# echo $?
1
# [ 10 -eq 10 ]
# echo $?
0
字符串比较符
运算符
描述
示例
==
等于
[ "a" == "a" ]为 true
!=
不等于
[ "a" != "a" ]为 false
= 2 ))为 true
-n
字符串长度不等于 0 为真
VAR1=1;VAR2=""
[ -n "$VAR1" ]为 true
-z
字符串长度等于 0 为真
VAR1=1;VAR2=""
[ -z "$VAR1" ]为 false
str
字符串存在为真
VAR1=1;VAR2=""
[ $VAR1 ]为 true
||
或者
 
[ -z $a ] && echo yes || echo no
# [ -z $a ] && echo yes || echo no
yes
# [ -n $a ] && echo yes || echo no
yes
# 加了双引号才能正常判断是否为空
# [ -z "$a" ] && echo yes || echo no
yes
# [ -n "$a" ] && echo yes || echo no
no
# 使用了双中括号就不用了双引号
# [[ -n $a ]] && echo yes || echo no
no
# [[ -z $a ]] && echo yes || echo no
yes
文件测试
测试符 描述
-e 文件或目录存在为真 [ -e path ] path 存在为 true
-f 文件存在为真 [ -f file_path ] 文件存在为 true
-d 目录存在为真 [ -d dir_path ] 目录存在为 true
-r 有读权限为真[ -r file_path ] file_path 有读权限为 true
-w 有写权限为真[ -w file_path ] file_path 有写权限为 true
-x 有执行权限为真 [ -x file_path ] file_path 有执行权限为 true
-s 文件存在并且大小大于0为真 [ -s file_path ] file_path 存在并且大小大于 0为true
#判断/etc/fstab 是否为一个目录类型的文件
# [ -d /etc/fstab ]
# echo $?
1
 
#判断/etc/fstab是否为一般文件,如果返回值为0,则代表文件存在,反之
# [ -f /etc/fstab ]
# echo $?
0
布尔运算符
运算符
描述
示例

非关系,取反
[ ! 1 -eq 2 ]为 true
-a
和关系,在【】表达式中使用
[ 1 -eq 1 -a 2 -eq 2 ]为 true
-o
或关系,在【】表达式中使用
[ 1 -eq 1 -o 2 -eq 1 ]为 true
逻辑判断符
判断符
描述
示例
&&
逻辑和,在[[]]和(())表达式中或判断表达
式是否为真时使用
[[ 1 -eq 1 && 2 -eq 2 ]]为 true
(( 1 == 1 && 2 == 2 ))为 true
[ 1 -eq 1 ] && echo yes 如果&&前面表达式
为 true 则执行后面的
||
逻辑或,在[[]]和(())表达式中或判断表达
式是否为真时使用
[[ 1 -eq 1 ||2 -eq 1 ]]为 true
(( 1 == 1 ||2 == 2 ))为 true
[ 1 -eq 2 ] ||echo yes 如果||前面表达式为
false 则执行后面的
整数运算
运算符 描述
+ 加法
- 减法
* 乘法
/ 除法
%取余
运算表达式 :
$(())$((1=1))
$[ ] $
$(())表达式还有一个用途,三目运算:
在此处所谓的单双,指的是参与运算的运算数个数。
单目运算
* 如大多数编程语言中都有的 i++、i-- 就是一种典型的单目运算。逻辑运算中的“非”运算,即 !a
,也是一种单目运算。
二目运算
* 二目运算同理,a + b , a - b , a ∩ b 等等
三目运算
* 三目运算稍复杂一些,下面给出一个表达式然后尽量通俗的解释:
status = hungry ? eat : notEat
这个表达式可以理解成:
* 肚子饿吗?
* 如果饿的话(status = hungry),就去吃饭。
* 如果不饿 (status != hungry),就不吃了。
* 参与运算的运算数有:hungry、eat、notEat三个。
 
# 如果条件为真返回 1,否则返回 0
# echo $((10))
1
指定输出数字:
# echo $((1>0?1:2))
1
# echo $((1 /dev/null
if [ $? -eq 0 ]
then
echo "$SER2 is running"
else
echo "$SER2 is not running"
fi
# chmod +x httpd.sh
# ./httpd.sh
httpd is running
##方法三:
# vim http1.sh
#!/bin/bash
if systemctl status httpd &> /dev/null
then
echo "service is running"
else
echo "service is down"
fi
# ./http1.sh
service is running
多分支
if 条件表达式
then
命令
elif 条件表达式
then
命令
else
命令
fi

发送邮件
 
dnf -y install postfix s-nail
vim /etc/s-nail.rc
#在文件最后添加
set from=295255180@qq.com #你的邮箱
set smtp=smtp.qq.com
set smtp-auth-user=295255180@qq.com #你的邮箱
set smtp-auth-password=gostoxmhcmkzcabb #你的邮箱授权码
set smtp-auth=login
#发送测试邮件
echo "123" | mail -s hihh 你的收件邮箱地址
#发送时候会报错,因为是老版本的写法,但是可以正常用
 

循环语句
循环for
for 变量名 in 取值列表
do
命令
done
示例:
#!/bin/bash
for i in {1..3}
do
echo $i
done
for 的语法也可以这么写:
#!/bin/bash
for i in "$@" # $@是将位置参数作为单个来处理
{
echo $i
}
# bash test.sh 1 2 3
1
2
3
默认 for 循环的取值列表是以空白符分隔,即系统变量里的$IFS:
#!/bin/bash
for i in 12 34
do
echo $i
done
# bash test.sh
12
34
以命令结果作为列表
#!/bin/bash
for file in $(ls) 这里可以写成`ls`
do
echo $file
done
如果想指定分隔符,可以重新赋值$IFS 变量:
#!/bin/bash
OLD_IFS=$IFS
IFS=":"
for i in $(head -1 /etc/passwd)
do
echo $i
done
IFS=$OLD_IFS # 恢复默认值
# bash test.sh
root
x
00
root
/root
/bin/bash
for 循环还有一种 C 语言风格的语法,常用于计数、打印数字序列:for (( expr1 ; expr2 ; expr3 )) ; do list ;done
#!/bin/bash
for ((i=1;i /dev/null && echo $user is exist || { useradd $user ; echo
$user
is created; }
done
 
示例10: 批量创建用户和并设置随机密码
#cat user_for.sh
#!/bin/bash
for i in {1..10};do
useradd user$i
PASS=`cat /dev/urandom | tr -dc '[:alnum:]' |head -c12`
echo $PASS | passwd --stdin user$i &> /dev/null
echo user$i:$PASS >> /data/user.log
echo "user$i is created"
done
 
示例11: 九九乘法表
#cat 9x9_for.sh
#!/bin/bash
for i in {1..9};do
for j in `seq $i`;do
echo -e "${j}x${i}=$\t\c"
done
echo
done
 
示例12:99乘法表实现过程
#思路
步骤一:
99乘法表中开始为1x1=1,最后的值为 9x9=81,所以需要两个变量i,j。且i和j的值由1都变为i,并
且做了乘法运算。
#!/bin/bash
#99
for i in {1..9}
do
for j in {1..9}
do
echo "$i*$j=$"
done
done
#执行结果,不是我们想要的。首先运算结果上有很多冗余数据,其次显示视图不符合要求
 
步骤二:删除冗余数据

分析可知,冗余数据出现在每次i都循环了9次。如果使得j
页: [1]
查看完整版本: shell脚本