shell语言:解释型语言,不需要编译,运行效率较低
C语言:描述性语言,调用底层函数,通过编译进行执行,更接近系统语言,运行效率远远高于shell语言
shell脚本的意义:
1)记录命令执行的过程和执行逻辑,以便以后重复执行
2)脚本可以批量处理主机(ansible也可实现)
3)脚本可以定时处理主机
Linux 系统中的 Shell 是一个特殊的应用程序,它介于操作系统内核与用户之间,充当 了一个“命令解释器”的角色,负责接收用户输入的操作指令(命令)并进行解释,将需要执 行的操作传递给内核执行,并输出执行结果。 常见的 Shell 解释器程序有很多种,使用不同的 Shell 时,其内部指令、命令行提示符 等方面会存在一些区别。
[root@localhost ~]#cat /etc/shells
#查看当前系统支持的Shell
/bin/sh
/bin/bash
/sbin/nologin
/usr/bin/sh
/usr/bin/bash
/usr/sbin/nologin
/bin/tcsh
/bin/csh
vim /etc/hostname
carter.org
hostnamectl hostname carter.org
ip a s ens32
ifconfig ens32
nmcli device show ens32
nmcli device status
nmcli connection show ens32
设置dncp网络工作模式
nmcli connection add con-name ens32 \
type ethernet ifname eth32\
ipv4.method auto
设置静态网络工作模式
nmcli connection add con-name ens32 \
type ethernet ifname eth32 ipv4.method manual \
ipv4.addresses 172.25.254.100/24 \
ipv4.gateway 172.25.254.2
nmcli connection modify ens32 ipv4.addresses 172.25.254.200/24
nmcli connection reload
nmcli connection up ens32
连续打印3个数字
seq 1 3
1
2
3
指定打印格式
seq -f "%03g" 1 3
001
002
003
设定打印步长
seq 1 2 10
1
3
5
7
9
seq 1 9 > test
tac test
9
8
7
6
5
4
3
2
1
打印字符
[root@carter ]# printf "hello world"
hello world[root@carter mnt]#
打印字符指定格式
[root@carter ]# printf “hello world\n"
hello world
[root@carter ]# printf "hello\tworld\n"
hello world
打印百分号
[root@carter ]# printf "3%%\n"
3%
打印整数,浮点数
[root@carter ]# printf "%.0f" "3.1415926"
3
[root@carter mnt]# printf "%.1f \n" "3.1415926"
3.1
echo
打印字符
[root@carter ~]# echo "hello world"
hello world
不换行打印
[root@carter ~]# echo -n "hello world"
hello world[root@carter ~]#
解析转义字符
[root@carter ~]# echo -e "hello\tworld"
查看wget版本
[root@carter ~]# wget -V
下载文件
[root@carter ~]# wget
https://dldir1.qq.com/qqfile/qq/QQNT/Linux/QQ_3.2.7_240403_x86_64_01.rpm
[root@carter ~]# wget
https://dldir1.qq.com/qqfile/qq/QQNT/Linux/QQ_3.2.7_240403_x86_64_01.rpm \
-O /mnt/qq.rpm
限速下载
[root@carter ~]# wget
https://dldir1.qq.com/qqfile/qq/QQNT/Linux/QQ_3.2.7_240403_x86_64_01.rpm -O \
/mnt/qq.rpm \
--limit-rate 1k
断点续传
[root@carter ~]# wget
https://dldir1.qq.com/qqfile/qq/QQNT/Linux/QQ_3.2.7_240403_x86_64_01.rpm -O \
/mnt/qq.rpm \
--limit-rate 1k \
-c
后台下载
[root@carter ~]# wget
https://dldir1.qq.com/qqfile/qq/QQNT/Linux/QQ_3.2.7_240403_x86_64_01.rpm -O \
/mnt/qq.rpm \
--limit-rate 1k \
-b
[root@carter ~]# tail -f wget-log
下载整个站点
[root@carter ~]# wget -r -O /mnt/baidu http://www.baidu.com
检测站点是否存活
[root@carter ~]# wget -q -T 3 -t 2 --spider http://www.baidu.com
-V: 查看wget的版本
-O|--output-document=FILE 将下载的内容写入到文件中
-c,--continue 支持断点续传
-b 后台下载
--limit-rate=RATE 限制下载速度
-q: 静默下载,即无信息输出
-T,--timeout=SECONDS: 下载的超时时间
-t,--tries=NUMBER: 设置重试次数(0 代表无限制)
--spider: 不下载任何文件
设置被监控的命令执行间隔
[root@carter ~]# watch -n2 ls /mnt
高亮显示变化区域
[root@carter ~]# watch -d ls /mnt
屏蔽顶部时间信息
[root@carter ~]# watch -t ls /mnt
xargs作用命令
[root@carter ~]# echo /mnt/ca{1..3} | touch
touch: missing file operand
Try 'touch --help' for more information.
[root@timinglee ~]# echo /mnt/ca{1..3} | xargs touch
多行输入单行输出
[root@carter ~]# vim /mnt/ca
a a a a a a
b b b b b b
c c c c c c
d d d d d d
e e e e e e
f f f f f f
[root@carter ~]# xargs < /mnt/ca
a a a a a a b b b b b b c c c c c c d d d d d d e e e e e e f f f f f f
指定每行输出个数
[root@carter ~]# xargs -n 3 < /mnt/ca
a a a
a a a
b b b
b b b
c c c
c c c
d d d
d d d
e e e
e e e
f f f
f f f
指定分隔符
[root@carter ~]# echo "ca:ca:ca" | xargs
ca:ca:ca
[root@carter ~]# echo "ca:ca:ca" | xargs -d:
ca ca ca
用字符代替接收值
[root@carter ~]# ls /mnt/* | xargs -Iword rm -fr word
脚本中通常用#号注释单行内容
[root@carter ~]# vim ca.sh
#!/bin/bash
#show some word
echo hello world
[root@carter ~]# sh ca.sh
hello world
多行注释
[root@carter ~]# vim ca.sh
#!/bin/bash
: "
注释1
注释2
注释3
"
echo hello world
[root@carter ~]# sh ca.sh
hello world
[root@carter ~]# cat /etc/passwd | grep root
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@carter ~]# grep root /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
# Date:创建日期
# Author:作者
# Mail:联系方式
# Function:功能
# Version:版本
不规范代码
#!/bin/bash
for i in 1 2 3
echo $i
done
规范代码
#!/bin/bash
for i in 1 2 3
echo $i
done
[root@carter ~]# vim ~/.vimrc
set ts=2 sw=2 ai et
map <F4> ms:call SHELLTITLE()<cr>'s
autocmd BufNewFile *.sh,*.script call SHELLTITLE()
func SHELLTITLE()
call append(0,"###############################################")
call append(1,"# Author: ca")
call append(2,"# Version: ")
call append(3,"# Date: ".strftime("%Y/%m/%d"))
call append(4,"# Mail: ca@westos.org")
call append(5,"# Function: ")
call append(6,"# ")
call append(7,"################################################")
call append(8,"")
call append(9,"#!/bin/bash")
endfunc
测试脚本内容
[root@carter ~]# vim ca.sh
#!/bin/bash
cat
方法1.
[root@carter ~]# . ca.sh &
[root@carter ~]# ps f
PID TTY STAT TIME COMMAND
17398 pts/2 Ss 0:00 -bash
17919 pts/2 T 0:00 \_ cat
17920 pts/2 R+ 0:00 \_ ps f
方法2.
[root@carter ~]# source ca.sh &
[root@carter ~]# ps f
PID TTY STAT TIME COMMAND
17398 pts/2 Ss 0:00 -bash
17919 pts/2 T 0:00 \_ cat
17920 pts/2 R+ 0:00 \_ ps f
测试脚本内容
[root@carter ~]# vim ca.sh
#!/bin/bash
cat
方法1.
[root@carter ~]# sh ca.sh &
[root@carter ~]# ps f
PID TTY STAT TIME COMMAND
17398 pts/2 Ss 0:00 -bash
17908 pts/2 T 0:00 \_ sh ca.sh
17909 pts/2 T 0:00 | \_ cat
方法2.
[root@carter ~]# chmod +x ca.sh
[root@carter ~]# /root/ca.sh
[root@carter ~]# /root/ca.sh &
[root@carter ~]# ps f
PID TTY STAT TIME COMMAND
17398 pts/2 Ss 0:00 -bash
17890 pts/2 T 0:00 \_ /bin/bash /root/ca.sh
17891 pts/2 T 0:00 | \_ cat
17892 pts/2 R+ 0:00 \_ ps f
[root@carter ~]# vim ca.sh
#!/bin/bash
hostname
echo $USER
date
cat #命令应为cal显示系统日历,用这个手残错误为例
pwd
直接执行脚本效果:
[root@carter ~]# sh ca.sh
carter.org
root
Sun Apr 7 04:27:05 AM EDT 2024
显示执行过程效果
[root@carter ~]# sh -x ca.sh
+ hostname
carter.org
+ echo root
root
+ date
Sun Apr 7 04:27:27 AM EDT 2024
+ cat
查看退出值
[root@carter ~]# ls /mnt/ca
ls: cannot access '/mnt/ca': No such file or directory
[root@carter ~]# echo $?
2
[root@carter ~]# touch /mnt/ca
[root@carter ~]# ls /mnt/ca
/mnt/ca
[root@carter ~]# echo $?
0
修改脚本退出值
未指定退出值
[root@carter ~]# vim ca.sh
#!/bin/bash
date
exit
[root@carter ~]# sh ca.sh
Sun Apr 7 04:32:50 AM EDT 2024
[root@carter ~]# echo $?
0
指定退出值
[root@carter ~]# vim ca.sh
#!/bin/bash
date
exit 66
[root@carter ~]# sh ca.sh
Sun Apr 7 04:32:50 AM EDT 2024
[root@ccarter ~]# echo $?
66
变量名:使用固定的名称,由系统预设或用户定义
变量值:能够根据用户设置、系统环境的变化而变化
自定义变量:由用户自己定义、修改和使用
特殊变量:环境变量,只读变量,位置变量,预定义变量
[root@localhost ~]#a=wyq
[root@localhost ~]#echo $a
wyq
[root@localhost ~]#a=cxk
[root@localhost ~]#echo $a
cxk
区分大小写
不能使程序中的保留字和内置变量:如:if, for,hostname 命令 a=
只能使用数字、字母及下划线,且不能以数字开头,注意:不支持短横线 “ - ”,和主机名相反
不要使用内置的变量,使用英文尽量使用词义通俗易懂,PATH
大驼峰 StudentFirstName
小驼峰 studentFirstName
下划线 student_name
赋值时使用双引号(" ")可以直接调用变量(双引号 弱引用 可以识别变量)
赋值时使用单引号(' ')变量$只会被认为是字符$ 不会调用变量(单引号 强引用 不能识别变量)
赋值时使用(``反撇在tab上面)命令替换,提取命令执行后的输出结 果 和$( ) 用法相同(反撇 调用命令的执行结果 反撇=$())
{}可以分隔变量值({ } 定义变量名的范围)
$CARTER #表示取$CARTER这个变量的值
[root@ca ~]# CARTER=1
[root@ca ~]# echo $CAARTER
1
[root@ca ~]# echo \#
#
[root@ca ~]# echo \# #
#
[root@ca ~]# echo \# \#
# #
[root@ca ~]# echo "# #"
# #
[root@ca ~]# echo "$5"
[root@ca ~]# echo '$5'
$5
函数级变量只在函数内生效通常用local来定义
vim test.sh
#!/bin/bash
ACTION () {
local a=1
echo $a
}
ACTION
echo $a
#sh test.sh
1
第二行显示为空
环境级别变量只在当前运行的shell中生效,shell关闭变量被释放
[root@ca ~]# export a=1
[root@ca ~]# vim test.sh
#!/bin/bash
echo $a
[root@ca ~]# sh test.sh
1
[root@ca ~]# exit
logout
[root@ca ~]# sh test.sh
显示为空
用户级变量只有登录系统的指定用户,此变量才生效
[root@ca ~]# useradd ca
[root@ca ~]# vim ~ca/.bash_profile
export a=1
[root@ca ~]# vim /mnt/test.sh
[root@ca ~]# sh /mnt/test.sh
显示为空
[root@ca ~]# su - ca
[lee@ca ~]$ sh /mnt/test.sh
1
系统级变量是系统中的永久设定,所有用户都可以使用,系统变量通常被保存到/etc/profile中
vim /etc/profile.d/a.sh
#!/bin/bash
export b=1
[root@ca ~]# source /etc/profile.d/a.sh
[root@ca ~]# vim /mnt/test.sh
#!/bin/bash
echo $b
[root@ca ~]# sh /mnt/test.sh
1
变量 说明
PATH 命令的搜索路径,以冒号作为分隔符
HOME 用户的家目录的路径,是cd命令的默认参数
COLUMNS 命令行编辑模式下可使用命令的长度
HISTFILE 命令历史的文件路径
HISTFILESIZE 命令历史中包含的最大行数
HISTSIZE history命令输出的记录数
LOGNAME|USER 当前用户的名字
SHELL 当前使用的shell
PWD 当前的工作目录
PS1 命令行提示符变量
在执行命令时如果想让指定命令优先执行可以使用 $(cmd) 或 ``
[root@carter ~]# echo your hostname is hostname
your hostname is hostname
[root@carter ~]# echo your hostname is $(hostname)
your hostname is carter.org
[root@carter ~]# echo your hostname is `hostname`
your hostname is carter.org
[root@carter ~]# My_Hostname=`hostname`
[root@carter ~]# mY_Hostname=$(hostname)
[root@carter ~]# echo $My_Hostname $mY_Hostname
carter.org carter.org
变量 说明
$# 命令行的参数的个数
$0 当前脚本的名称
$n 当前传递给脚本的第n个参数,比如$1表示脚本的第一个参数,$2表示脚本的第二个参数……
$* 以“参数1 参数2 参数3”的形式返回所有参数的值
$@ 以“参数1” “参数2” “参数3” 的形式返回所有参数的值
vim test.sh
!/bin/bash
echo '$#' is $#
echo '$0' is $#
echo '$1' is $1
echo '$2' is $2
echo '$3' is $3
echo '$@' is $@
echo '$*' is $*
sh test.sh carter linux ca
$# is 3
$0 is 3
$1 is carter
$2 is linux
$3 is ca
$@ is carter linux ca
$* is carter linux ca
[root@carter ~]# echo $$
46058
[root@carter ~]# ps
PID TTY TIME CMD
46058 pts/0 00:00:00 bash
46170 pts/0 00:00:00 ps
[root@carter ~]# echo $?
0
[root@carter ~]# ls haha
ls: cannot access 'haha': No such file or directory
[root@carter ~]# echo $?
2
交互赋值单个变量
[root@carter ~]# read A
hello
[root@carter ~]# echo $A
hello
交互赋值多个变量
[root@carter ~]# read A B C
hello ca linux
[root@carter ~]# echo $A $B $C
hello ca linux
交互赋值数组
[root@carter ~]# read -a array
hello ca linux
[root@carter ~]# echo ${array[*]}
hello ca linux
[root@carter ~]# echo ${array[0]}
hello
[root@carter ~]# echo ${array[1]}
ca
[root@carter ~]# echo ${array[2]}
linux
交互赋值并显示提示符
[root@carter ~]# read -p "Please input word: " WORD
Please input word: test
[root@carter ~]# echo $WORD
test
隐藏赋值内容
[root@carter ~]# read -p "Please input word: " -s WORD
Please input word: [root@carter ~]# echo $WORD
hello
设置超时时间
[root@carter ~]# read -t 5 -p "Please input word: " WORD
设置赋值长度
[root@carter ~]# read -n 3 -p "Please input word: " WORD
指定录入结束符
[root@carter ~]# read -d "." a
123456.
-a 读取的内容存入数组
-d 持续读取直到读入 DELIM 变量中的第一个字符,而不是换行符
-n/N 读取N个字符
-p 指定提示信息,用于等待输入
-r 不允许反斜杠转义任何字符
-s 从标准输入中读取密码而不在屏幕上显示输入的字符
-t 设置读取输入的超时时间,单位为秒
定义变量为一组内容,中间的元素用空格隔开
A=(1 2 3 4 5)
取变量的所有元素
[root@carter ~]# echo ${a[*]}
1 2 3 4 5
[root@carter ~]# echo ${a[@]}
1 2 3 4 5
取数组的第一个元素
[root@carter ~]# echo ${a[0]}
1
取数组的最后一个元素
[root@carter ~]# echo ${a[-1]}
5
取数组的第1-3个元素
[root@carter ~]# echo ${a[*]:0:3}
1 2 3
查看数组的元素个数
[root@carter ~]# echo ${#a[@]}
5
管理数组元素
[root@carter ~]# a[0]=6 #更改数组第一个元素为6
[root@carter ~]# echo ${a[@]}
6 2 3 4 5
[root@carter ~]# a[5]=6 #添加数组中的第六个元素为6
[root@carter ~]# echo ${a[@]}
6 2 3 4 5 6
[root@carter ~]# unset a[0] #删除数组中第一个元素
[root@carter ~]# echo ${a[@]}
2 3 4 5 6
[root@carter ~]# unset a #删除整个数组
表达式 说明
${parameter} 返回变量的内容
${#parameter} 返回变量内容的长度(按字符)
${paramater:offset} 在变量${parameter}中,从位置offset之后开始提取子串到结尾
${paramater:offset:length} 在变量${parameter}中,从位置offset之后开始提取长度为length的子串
${parameter#word} 从变量${parameter}开头开始删除最短匹配的word子串
${parameter##word} 从变量${parameter}开头开始删除最长匹配的word子串
${parameter%word} 从变量${parameter}结尾开始删除最短匹配的word子串
${parameter%%word} 从变量${parameter}结尾开始删除最长匹配的word子串
${parameter/pattern/string} 使用string代替第一个匹配的pattern
${parameter//pattern/string} 使用string代替所有匹配的pattern
设定实验变量
str="/carter/ca/test.tar.gz"
取所有字符串
echo ${str}
统计字符串长度
[root@carter ~]# echo ${#str}
21
从指定位置取值到结尾
[root@carter ~]# echo ${str:5}
/ca/test.tar.gz
从指定位置取指定长度的字符
[root@carter ~]# echo ${str:1:3}
car
[root@carter ~]# echo ${str::3}
/ca
从倒数第3个字符向后取2个字符
[root@lee ~]# echo ${str:0-3:2}
.c
取最后5个字符
[root@carter ~]# echo ${str:0-5}
ar.gz
从开头检索最近匹配字符串并删除
从先到后
[root@carter ~]# echo ${str#*/}
carter/ca/test.tar.gz
从后到前
[root@carter ~]# echo ${str%%/*}
输出为空
从开头检索最远匹配字符串并删除
从前到后
[root@carter ~]# echo ${str##*/}
test.tar.gz
从后到前
[root@carter ~]# echo ${str%/*}
/carter/ca
替换字符
[root@carter ~]# echo ${str/./@}
/carter/ca/test@tar.gz
[root@carter ~]# echo ${str//./@}
/carter/ca/test@tar@gz
1.解决代码重复问题
#!/bin/bash
echo -e "\033[31mread \033[0m"
echo -e "\033[32mread \033[0m"
echo -e "\033[33mread \033[0m"
echo "====== function ============="
ECHO ()
{
echo -e "\033[$1m$2\033[0m"
}
ECHO 31 read
ECHO 32 grean
ECHO 33 yello
2.代码无线循环
#!/bin/bash
ACTION()
{
read -p "Please input word: " WORD
echo $WORD
ACTION
}
ACTION
运算命令与符号 意义 说明
(()) 用于整数运算的常用运算符 在(())中使用变量时可以去掉变量前的$符号
let 用于整数运算 使用let命令可以执行一个或者多个算术表达
式,其中的变量名毋需使用$符号
expr 可用于整数运算,但还有很多其他的额外功能 使用expr时,运算符及用于计算的数字左右
都至少有一个空格,否则会报错;。
bc linux下的一个计算器程序(适合整数及小数运算) 系统中的计算器可以计算小数,二进制等
$[] 用于整数运算
awk awk既可以用于整数运算,也可以用于小数运算
declare 定义变量值和属性,-i参数可以用于定义整形变量,做运算
[root@carter ~]# echo a=((1 + 2))
[root@carter ~]# echo $a
3
[root@carter ~]# let a=1+2
[root@carter ~]# echo $a
3
[root@carter ~]# expr 1 \* 2
2
[root@carter ~]# echo "scale=2;1/2" | bc
.50
[root@carter ~]# echo "obase=2;ibase=10;2"|bc
10
[root@carter ~]# echo $[1+1]
2
[root@carter ~]# awk 'BEGIN{print 1.88/29}'
0.0648276
[root@carter ~]# declare -i a=1+1
[root@carter ~]# echo $a
2
运算符 说明
+、- 求和、差
*、/、% 求乘积,商,余数
** 幂运算,例如3**3是求3的立方,即27
+=、-=、*=、/=、%= 例a+=1相当于a=a+1
++variable、--variable 先将变量variable的值加1,然后再赋给variable; 先将变量variable
的值减1,然后再赋给variable
variable++、variable-- 先使用variable的值,然后再将该变量的值加1; 先使用variable的值,然后
再将该变量的值减1
[root@carter mnt]# echo $((1+1))
2
[root@carter mnt]# echo $((2-1))
1
[root@carter mnt]# echo $((2*2))
4
[root@carter mnt]# echo $((2**3))
8
[root@carter mnt]# echo $((2/3))
0
[root@carter mnt]# echo $((2%3))
2
#用for语句验证 +=、-=、*=、/=、%=
vim test.sh
!/bin/bash
for i in {1..5}
do
((n+=i))
echo $n
done
[root@carter mnt]# sh test.sh
1 #n没有值 i=1 经过运算n=1
3 #n=1 i=2 经过运算n=3
6
10
#用for语句验证++variable、--variable variable++、variable--
[root@carter ~]# for ((n=1;n<=5;n++))
> do
> echo $n
> done
1
2
3
4
5
数A <<1 >>1 a<<=1 a>>=1
0 0 0 0 0
0 1 0 1 0
1 0 0 0 0
0 0 1 0 1
echo $((2<<1))
4
echo $((2>>1))
1
a=2
$((a>>=1))
echo $a
4
a=2
$((a《《=1))
echo $a
1
数A 数B a&b a|b a^b ~a
0 0 0 0 0 1
0 0 0 0 0 1
0 1 0 1 1 1
1 0 0 1 1 0
echo $((1&2))
0
echo $((1|2))
3
echo $((1^2))
3
echo $((~1))
-2
数A A&=2 A|=2 A^=2
0 0 0 0
0 0 0 0
0 0 1 1
1 0 1 1
[root@carter ~]# a=1
[root@carter ~]# ((a&=2))
[root@carter ~]# echo $a
0
[root@carter ~]# a=1
[root@carter ~]# ((a|=2))
[root@carter ~]# echo $a
3
[root@carter ~]# a=1
[root@carter ~]# ((a^=2))
[root@carter ~]# echo $a
3