Shell脚本内建命令

2022-09-28 19:39:39 浏览数 (1)

[TOC]

0x00 shell 内建命令
type 命令

描述:查看命令相关信息类型

代码语言:javascript复制
# (1) 查看命令类型
type -a complete
#complete 是 shell 内嵌
eval 命令 (慎用)

描述:以shell命令的形式执行参数。将ARGs组合成一个字符串,将结果作为shell的输入,并执行生成的命令。

间接引用变量:eval会对后面的cmdLine进行两遍扫描

  • 如果第一遍扫描后cmdLine是个普通命令则执行此命令;
  • 如果cmdLine中含有变量的间接引用,则保证间接引用的语义。

基础语法:

代码语言:javascript复制
eval [arg ...]

退出状态:返回命令的退出状态,如果命令为空则返回成功。

代码语言:javascript复制
#基础示例1:可以用于回显简单变量或复杂变量。
NAME=ZONE
eval echo $NAME #等价于echo $NAME  = ZONE

#基础示例2:
name=weiyigeek
weiyigeek=shellPrograming
eval var=$$name  #实际赋值的变量为$weiyiyeek
echo $var #shellPrograming


#示例3.两次扫描test.txt内容:hello shell world!
myfile="cat test.txt"
echo $myfile       #result:cat test.txt
eval echo $myfile  #result:hello shell world! 会进行执行cat命令后再进行输出内容
read 命令

描述:read命令从键盘读取变量的值,通常用在shell脚本中与用户进行交互的场合 该命令可以一次读取多个变量的值,变量和输入的值都需要使用空格隔开,在read命令后面如果没有指定变量名,读取的数据将被自动赋值给特定的变量;

语法选项:

代码语言:javascript复制
read [选项] [变量名]
#选项
-p "提示信息":等待read输入时候提示信息;
-t <秒数>:read命令会一直等待用户输入,使用此选项可以指定等待时间
-n 字符数:read命令只接受指定的字符数就会执行
-a:"输入字符到某一数组里"
-d:"指定分隔符,来结束输入"
-r:"允许输出包含反斜杠"
-s:密码类型输入不显示

实际案例:

代码语言:javascript复制
#示例1.标准输入
$read
whoami
$echo $REPLY  #从标准输入读取一行并赋值给特定变量REPLY。  whoami

$read param1 #从标准输入读取一行并赋值给指定变量param1。
this is a read
$echo $param1   #this is a read

$read p1 p2  #从标准输入读取输入到第一个空格或者回车
I loveyou
$echo "${p1} ${p2}" #将输入的第一个单词放到变量p1中,并将该行其他的输入放在变量p2中。I loveyou
read one two three
1 2 3                   #在控制台输入1 2 3,它们之间用空格隔开。
#echo "one = $one, two = $two, three = $three"
#one = 1, two = 2, three = 3


#示例2.常用参数
read -p "text" -t 3  #打印提示(text),等待输入,并将输入存储在REPLY中。指定读取等待时间为3秒。
read -r line #允许输入包含反斜杠。

read -d ":" var  #用定界符":"结束输入行。
i love study Computer:
$echo $var  #i love study Computer rt

read -a arrayname  #把单词清单读入arrayname的数组里。(非常有用)
i love you
$echo ${arrayname} ${arrayname[2]}   #i you
$echo ${arrayname[*]}  #i love you

read -n 2 var  #从输入中读取两个字符并存入变量var,不需要按回车读取。
ls
$echo $var  #ls


#示例3.进阶使用 补充一个终端输入密码时候,不让密码显示出来的例子。
#!/bin/bash
read -p "输入密码:" -s pwd   #补充一个终端输入密码时候,不让密码显示出来的例子。
输入密码:
echo password read, is "$pwd" #password read, is whoami

#方法二:采用stty选项
其中选项-echo禁止将输出发送到终端,而选项echo则允许发送输出。
#!/bin/bash
stty -echo
read -p "输入密码:" pwd
stty echo
echo
echo 输入完毕。

WeiyiGeek.read测试


declare 命令

描述:用于声明和显示已存在的shell变量类型。当不提供变量名参数时显示所有shell变量,declare命令若不带任何参数选项,则会显示全部的shell变量与函数(与执行set指令的效果相同)。

declare命令(别名typeset)属shell内建命令用于申明shell变量并设置变量属性,或查看已定义的shell变量和函数的(弱类型,默认字符串型)

代码语言:javascript复制
#语法
declare [ /-] [选项] 变量表达式
#变量表达式:声明shell变量,格式为"变量名=值"。

#参数
 /-:"-"可用来指定变量的属性," "则是取消变量所设的属性;
-a:将变量声明为数组类型(Array);
-i:[设置值]可以是数值类型(Int),字符串或运算式;
-p:显示指定变量的被声明得类型;
-f:仅显示函数; 
-r:将变量设置为只读(临时生效);
-x:指定的变量会成为环境变量,可供shell以外的程序来使用;

操作实例:

代码语言:javascript复制
#1.定义一个字符串shell变量
$ declare name="Weiyigeek"
$ echo $name    #只是当前shell生效,并不存在系统环境变量种
Weiyigeek

#2.定义一个整形(可计算的)shell变量
$ declare -i c=5 6
$ echo $c
11

#3.定义一个数组
$ declare -a temp[2]=TCP
$ temp[1]=Protocol
$ echo ${temp[*]}
Protocol TCP

#4.定义系统变量
declare -x ppfile=/usr/bin/file.sh   # 与export作用相同,但其实Export也是引用declare命令的作用.
env | grep ppfile    #在系统环境变量种
ppfile=/usr/bin/file.sh

declare -r pfile=/usr/bin/file.sh  #定义只读变量 (临时生效,且不能被unset移除)只是在当前shell中生效
env | grep pfile    #申明变量步骤在系统环境变量中

#4.显示变量被申明的名称类型
$declare -p name
declare -- name="Weiyigeek"
$declare -p c
declare -i c="11"
readonly 命令

描述:使用 readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变。

代码语言:javascript复制
#示例1.下面的例子尝试更改只读变量,结果报错:
#!/bin/bash
myUrl="http://see.xidian.edu.cn/cpp/shell/"
readonly myUrl
myUrl="http://see.xidian.edu.cn/cpp/danpianji/"

# -bash: myUrl: 只读变量
stty 命令

描述: stty命令修改终端命令行的相关设置。

代码语言:javascript复制
#语法
stty(选项)(参数)

#选项
-a:以容易阅读的方式打印当前的所有配置;
-g:以stty可读方式打印当前的所有配置

实际案例:

代码语言:javascript复制
#在命令行下,禁止输出大写的方法:
stty iuclc     #开启
stty -iuclc    #恢复

#在命令行下禁止输出小写:
stty olcuc    #开启
stty -olcuc   #恢复

#忽略回车符:
stty igncr     #开启
stty -igncr    #恢复


#示例1.打印出终端的行数和列数根据具体变化而变化;
$stty -a #查看所有符号定义以及快捷键
# speed 38400 baud; rows 30; columns 118; line = 0;
$stty size
# 24 100


#示例2.改变Ctrl D的方法:
stty eof "string"  #系统默认是Ctrl D来表示文件的结束,而通过这种方法,可以改变!


#示例3. 屏蔽显示
stty -echo   #禁止回显
stty echo    #打开回显
#测试方法:stty -echo;read;stty echo;read


#示例4. 更简单的方法就是利用read命令的-t选项:
$stty -g  #save current settings
4d00:5:bf:8a3b:3:1c:8:15:4:0:1:0:11:13:1a:0:12:f:17:16:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
stty -icanon min 0 time 100  #set 10seconds,not 100seconds
eval read varname            #=read $varname
stty "$old_stty_settings"    #recover settings

#或者
read -t 10 varname
tput 命令

描述:tput 命令将通过 terminfo 数据库对您的终端会话进行初始化和操作 通过使用 tput,您可以更改几项终端功能,如移动或更改光标、更改文本属性,以及清除终端屏幕的特定区域

什么是terminfo数据库? 答:UNIX系统上的数据库用于定义终端和打印机的属性及功能,包括各设备(例如终端和打印机)的行数和列数以及要发送至该色板的文本属性; UNIX中的几个常用程序都依赖terminfo数据库提供这些属性以及许多其他类型,包括vi和emacs编辑器以及curses和man程序;

光标属性 在 UNIX shell 脚本中或在命令行中,移动光标或更改光标属性可能是非常有用的; 在向某一设备显示数据时,很多时候您并不希望看到光标,将光标转换为不可见可以使数据滚动时的屏幕看起来更整洁。

  • 要使光标不可见请使用 civis 选项(例如,tput civis)。
  • 在数据完全显示之后可以使用 cnorm 选项将光标再次转变为可见。

WeiyiGeek.civis与cnorm

代码语言:javascript复制
#(1)字符串输出参数设置_
tput bel       #警铃 
tput blink     #闪烁模式 
tput bold      #粗体 
tput clear     #清屏 

tput civis     #隐藏光标 
tput cnorm     #不隐藏光标 

tput cup       #移动光标到屏幕位置(x,y) 
tput el        #清除到行尾 
tput ell       #清除到行首 

tput smso      #启动突出模式 
tput rmso      #停止突出模式 
tput smul      #开始下划线模式 
tput rmul      #结束下划线模式 
tput sc        #保存当前光标位置 
tput rc        #恢复光标到最后保存位置

tput sgr0      #正常屏幕 
tput rev       #逆转视图

tput  setaf     #字符颜色
tput  setab     #背景颜色

#(2)数字输出参数设置
cols      #列数目
ittab     #设置宽度
lines     #屏幕行数

#(3)布尔输出参数设置
chts      #光标不可见
hs        #具有状态行

移动光标 描述:使用 tput 可以方便地实现在各设备上移动光标的位置。通过在 tput 中使用 cup 选项或光标位置,您可以在设备的各行和各列中将光标移动到任意 X 或 Y 坐标,以设备左上角的坐标为 (0,0)起点

代码语言:javascript复制
#示例1.要在设备上将光标移动到第 5 列 (X) 的第 1 行 (Y)
$tput cup 5 1

#示例2.此命令将使光标移动到第 23 列上的第 45 行。
$tput cup 23 45

移动光标并显示信息 另一种有用的光标定位技巧是移动光标,执行用于显示信息的命令,然后返回到前一光标位置:

代码语言:javascript复制
(tput sc ; tput cup 23 45 ; echo "Input from tput/echo at 23/45" ; tput rc) # 将信息显示到 stdout 中。

注意:由于本文首先详细介绍了通过命令行执行 tput,因此您可能会觉得在自己的 subshell 中执行命令要比单独执行每条命令然后在每条命令执行之前显示提示更简洁。

WeiyiGeek.基础示例

文本属性 通过以下方式更改文本属性:使文本加粗、在文本下方添加下划线、更改背景颜色和前景颜色,以及逆转颜色方案等。

要更改文本的颜色,请使用 setb 选项(用于设置背景颜色)和 setf 选项(用于设置前景颜色)以及在 terminfo 数据库中分配的颜色数值: 0:黑色 1:蓝色 2:绿色 3:青色 4:红色 5:洋红色 6:黄色 7:白色

WeiyiGeek.颜色数值

实际案例:

代码语言:javascript复制
#示例1.执行以下示例命令可以将背景颜色更改为黄色,将前景颜色更改为红色:
tput setb 6 tput setf 4
#要反显当前的颜色方案,只需执行
tput rev  #有时仅为文本着色还不够,也就是说,您想要通过另一种方式引起用户的注意。


#示例2.可以通过两种方式达到这一目的:一是将文本设置为粗体,二是为文本添加下划线。
* 要将文本更改为粗体 :bold 选项
* 要开始添加下划线 : smul 选项
* 在完成显示带下划线的文本后 :rmul 选项

$ tput bold;echo "bold";tput smul; echo "下划线"; tput rmul; echo "下划线文本"

使输出的字符串有颜色,底色,加粗:

代码语言:javascript复制
#!/bin/bash
printf $(tput setaf 2; tput bold)'color shownn'$(tput sgr0)

for((i=0; i<=7; i  )); do
    echo $(tput setaf $i)"show me the money"$(tput sgr0)
done

printf 'n'$(tput setaf 2; tput setab 0; tput bold)'background color show'$(tput sgr0)'nn'

for((i=0,j=7; i<=7; i  ,j--)); do
    echo $(tput setaf $i; tput setab $j; tput bold)"show me the money"$(tput sgr0)
done

exit 0

WeiyiGeek.示例

输出格式控制函数:

代码语言:javascript复制
#!/bin/bash

# $1 str       print string
# $2 color     0-7 设置颜色
# $3 bgcolor   0-7 设置背景颜色
# $4 bold      0-1 设置粗体
# $5 underline 0-1 设置下划线

function format_output(){
    str=$1
    color=$2
    bgcolor=$3
    bold=$4
    underline=$5
    normal=$(tput sgr0)  #恢复正常水平

    case "$color" in
        0|1|2|3|4|5|6|7)
            setcolor=$(tput setaf $color;) ;;
        *)
            setcolor="" ;;
    esac

    case "$bgcolor" in
        0|1|2|3|4|5|6|7)
            setbgcolor=$(tput setab $bgcolor;) ;;
        *)
            setbgcolor="" ;;
    esac

    if [ "$bold" = "1" ]; then
        setbold=$(tput bold;)
    else
        setbold=""
    fi

    if [ "$underline" = "1" ]; then
        setunderline=$(tput smul;)
    else
        setunderline=""
    fi

    printf "$setcolor $setbgcolor $setbold $setunderline $str $normaln"
}

format_output "Yesterday Once More" 3 5 1 1  # 输出格式控制函数
exit 0

WeiyiGeek.基础示例

光标属性例子

代码语言:javascript复制
#!/bin/bash
tput clear  # clear the screen
tput cup 3 15  # Move cursor to screen location X,Y (top left is 0 0)
tput setaf 3  # a foreground colour using ANSI escape
echo "XYX Corp LTD."
tput sgr0 #恢复正常
tput cup 5 17  #移动光标
tput rev  # Set reverse video mode
echo "M A I N - M E N U"
tput sgr0
tput cup 7 15
echo "1. User Management"
tput cup 8 15
echo "2. service Management"
tput cup 9 15
echo "3. Process Management"
tput cup 10 15
echo "4. Backup"
tput bold # Set bold mode
tput cup 12 15
read -p "Enter your choice [1-4] " choice
tput clear
tput sgr0
tput rc  #恢复光标到最后保存位置

WeiyiGeek.示例演示


0x01 shell 计算命令

描述:除了上面的declare命令可以计算数值外还有其他的一些命令如let/expr以及bc(还能进制转换)等等非常强大;

let 运算

描述:bash中用于计算的工具提供常用运算符还提供了方幂**运算符。 在变量的计算中不需要加上$来表示变量,如果表达式的值是非0,那么返回的状态值是0;否则,返回的状态值是1。

语法:

代码语言:javascript复制
let arg [arg ...]    #arg代表运算式

实际案例:

代码语言:javascript复制
#示例0。基础运算
$ let "t4 = 8 % 6";echo $t4  #2
$ let "t4 = 8 / 6";echo $t4  #1

#示例1.自加操作,自减操作
no=1024
let no  ;echo $no  #1025 #  i还是i  ,let都是返回计算后的值
let no--;echo $no  #1024

#示例2.简写形式
let no =10;echo $no  #1033
let no-=20;echo $no  #1013   分别等同于let no=no 10,let no=no-20

#示例3.直接采用变量名进行计算
let a=5 4 b=9-3;echo $a $b  #操作符左右不能有空格
let "t1 = ((a = 2   3, b = 2 - 1))";echo "t1 = $t1, a = $a, b = $b" #操作符合左右可以有空格
#t1 = 1, a = 5, b = 1 #t1是减表达最后一个计算的值赋给它

#示例4.阶乘
let t2=a**3;echo $t2     #125
let "t3 = a ** 3";echo $t3 #125

#示例5.其他计算
let "t4 = a || 1";echo $t4 #1
let "t4 = a && 0";echo $t4 #0
let "t4 = 8 | 7";echo $t4  #15

注意事项:

  • 在使用let命令进行变量计算时候,可以加$变量名也可以直接是变量名;
  • 在使用let命令采用""包含的表达式里操作符左右两边可以存在空格,否则不能存在空格;
expr 命令

描述:一款表达式计算工具,使用它完成表达式的求值操作。注意点:expr的乘法运算是 *,且变量必须要加$

代码语言:javascript复制
#关键说明
length :获取变量或表达式的长度

实际案例:

代码语言:javascript复制
#示例1.基础运算
a=1;b=2
expr $a   $b  #3 
result=`expr 2   3`;echo $result  #5
result=`expr 2 * 3`;echo $result #6
result=`expr 2 / 3`;echo $result #0
result=`expr 2 % 3`;echo $result #2


#示例2.新方式逻辑运算符使用(expr 里面的可以直接执行命令-)
no1=0
result=$(expr $no1 && whoami);echo $result #0  逻辑与
result=$(expr $no1 || whoami);echo $result #0  Administrator 

#逻辑与。根据短路求值方式判断 如果为0,就不执行后面的whoami,否则执行
ww=`expr 1 && whoami`;echo $ww #1  Administrator 
#逻辑或。根据短路求值方式判断 ,如果为1(>0),直接为真后面的whoami不执行,否则执行
ww=`expr 12 || whoami`;echo $ww #12


#示例3.获取表达式长度或者变量长度 (重点)
$ num=1024
$ expr length '$num'  #4
$ expr length '12345678 987654321'  #18

注意事项

  • 逻辑与或短路求值的特性非常需要注意,还要知道expr中可以执行shell命令(在写脚本的时候需要注意安全意识)
bc 命令

描述:bash内置了对整数四则运算的支持,但是并不支持浮点运算,而bc计算命令算术操作高级运算工具,它可以执行浮点运算和一些高级函数;

语法参数:

代码语言:javascript复制
bc(选项)(参数)

#选项
-i:强制进入交互式模式;
-l:定义使用的标准数学库;
-w:对POSIX bc的扩展给出警告信息;
-q:不打印正常的GNU bc环境信息;

#参数
scale=2    #将bc输出结果的小数位设置为2位。
ibase=2/8/10/16   #指定输入的进制
obase=2/8/10/16  #将bc输出结果进行进制转换

#进制转换:
二进制,Binary, 缩写BIN或B表示。
八进制,Octal,缩写OCT或O,一种以8为基数的计数法,用O表示。
十进制,英文为Decimal System,缩写Dec或D,来源于希腊文Decem,用D表示。
十六进制,英文为,缩写HEX或用H表示。

实际案例:

代码语言:javascript复制
#示例1.执行浮点运算
echo "1.212*3" | bc  #3.636
echo "scale=2;3/8" | bc #0.37 小数位设置为2位。

#示例2.进制转换可以指定进制数及其数值:
#echo "obase=输出进制数;ibase=输入进制数;输入的数字" | bc
abc=192; echo "obase=2;$abc" | bc  #$执行结果为:11000000,用bc将十进制转换成二进制。
abc=11000000; echo "obase=10;ibase=2;$abc" | bc # 执行结果为:192,用bc将二进制转换为十进制。
echo "obase=16;ibase=10;30" | bc # 执行结果为: 1E
echo "obase=10;ibase=16;FF"|bc

#示例3. 计算平方和平方根:
echo "10^10" | bc
echo "sqrt(100)" | bc
echo "scale=2;sqrt(10)" | bc

#示例4.交互执行
bc
# bc version 1.06.95
1 3 5
9
10*52
520
10^2
100
# bc 默认仅仅输出整数
10/100
0
# 如果要输出小数必须要执行scale=number即指定小数点后的位数;
scale=3
10/100
.100

128/256
.500

256*0.5
128.0

WeiyiGeek.BC示例


0x02 shell 判断选择
test 命令

描述:test命令是shell环境中测试条件表达式的实用工具,最短的定义可能是评估一个表达式,与[]功能差不多

  • 如果条件为真,则返回一个 0 值
  • 如果表达式不为真,则返回一个大于 0 的值 — 也可以将其称为假值。

tips:检查最后所执行命令的状态的最简便方法是使用 $? 值

基础语法:

代码语言:javascript复制
test [选项] 文件

#按文件类型进行判断:
$test -e file.txt
-e 该『文件名』是否存在?(常用) 
-f 该『文件名』是否为文件(file)?(常用) 
-d 该『文件名』是否为目录(directory)?(常用) 
-b 该『文件名』是否为一个 block device 装置? 
-c 该『文件名』是否为一个 character device 装置? 
-p 该『文件名』是否为一个 FIFO 管道(pipe) 文件? 
-L 该『文件名』是否为一个符号链接文件? 
-s 侦测该文件名是否为『非空白文件』 Empty File? 
-S 该『文件名』是否为一个 Socket (套接字) 文件? 


# 按文件权限进行判断
$test -r filename 
-r 侦测该文件名是否具有『可读』的属性? 
-w 侦测该文件名是否具有『可写』的属性? 
-x 侦测该文件名是否具有『可执行』的属性且存在? 
-u 侦测该文件名是否具有『SUID』的属性? 使可执行文件除了root以外的其他用户可执行,
-g 侦测该文件名是否具有『SGID』的属性? 使可执行文件除了root以外的其他用户组可执行,
-k 侦测该文件名是否具有『Sticky bit』的属性? 可建立但不可删除与更改,也可以设置不可建立但可以更改(目录中);


# 两个文件之间的比较
test file1 -nt file2 
-nt (newer than)判断 file1 是否比 file2 新 (New)
-ot (older than)判断 file1 是否比 file2 旧 (Old)
-ef 判断 file2 与 file2 是否为同一文件,可用在判断 hard link 的判定上。 主要意义在判定,两个文件是否均指向同一个 inode 号! 


# 判断表达式
-a 或 && :逻辑与,"而且"的意思,前后两个表达式都成立时整个测试结果才为真,否则为假
-o 或 || : 逻辑或,"或者"的意思,操作符两边至少一个为真时,结果为真,否为为假
! :逻辑否,当制定条件不成立时,返回结果为真
test 表达式1 –a 表达式2     #两个表达式都为真 返回0,否则返回1
test 表达式1 –o 表达式2     #两个表达式有一个为真
test 表达式1 ! 表达式2       #条件求反


# 判断字符串
test –n 字符串    #字符串的长度非零
test –z 字符串    #字符串的长度是否为零
test 字符串=字符串2       #字符串是否相等,若相等返回true
test 字符串==字符串2       #字符串是否相等,若相等返回true
test 字符串1!=字符串2      #字符串是否不等,若不等反悔false


#判断整数
test 整数1 -eq 整数2    #整数相等
test 整数1 -ge 整数2    #整数1大于等于整数2
test 整数1 -gt 整数2    #整数1大于整数2
test 整数1 -le 整数2    #整数1小于等于整数2
test 整数1 -lt 整数2    #整数1小于整数2
test 整数1 -ne 整数2    #整数1不等于整数2

实际案例:

代码语言:javascript复制
#实例1.shell中常见的test的用法
#! 反相状态,如 test ! -x file ,当 file 不具有 x(执行权限) 时,回传 true
$ test ! -x file.exsit ;echo $? #0 为真
$ test -x file.exsit ;echo $?   #1 为假

$ test -s file.exsit -a -f file.exsit;echo $?    #0  两则为真则为真
$ test -s file.exsit -a ! -f file.exsit;echo $?  #1  否则为假


#示例2.字符串判断
test -n "string";echo $? # 0  长度非0, 返回0
test -z "string";echo $? # 1  长度不为0,返回1
test "string" != "String";echo $?  #0
test "string" == "string";echo $?  #0
$test -n "web" && echo "is not null" ||  echo "is null"
#is not null
$test -n "" && echo "is not null" ||  echo "is null"
#is null
#非常注意 = 等号两边的空格
test "web" = "web" &&  echo "string is equal" ||  echo "string is not equal"
#string is equal        
test "web" = "web1" &&  echo "string is equal" ||  echo "string is not equal"
#string is not equal    


#示例3.整数判断
test 1 == 2;echo $?  #1 能使用 == != > < 捕获建议使用 -e1 -ne -gt -lt
test 1 == 1;echo $?  #0
test 1 != 1;echo $?  #1
test 1 != 2;echo $?  #0


#示例4.判断软硬链接
ln -s file.exsit /tmp/link.file
test -L link.file;echo $?   #0
test ! -L link.file;echo $? #1
test link.file -ef file.exsit;echo $? #判断是不是同一链接 0


#其他示例
$test 123 -eq 123 && echo "ture" || echo "false"     #判断AB相等 ture
$test 123 -eq 1234 && echo "ture" || echo "false"   #false
$test 123 -ne 1234 && echo "ture" || echo "false"     #判断A不等于B ture
$test 123 -le 1234 && echo "ture" || echo "false"     #判断A小于等于B ture
$test 123 -ge 1234 && echo "ture" || echo "false"     #判断A大于等于B false
$test 1234 -ge 1234 && echo "ture" || echo "false"   # >=  ture
$test 123 -gt 12 && echo "ture" || echo "false"         #判断A大于B  ture
$test 123 -lt 1234 && echo "ture" || echo "false"        #判断A小于B ture

0x03 系统信号管理
trap 命令

描述:允许你来指定shell脚本要监视并拦截的Linux信号,主要用于在脚本中处理信号是一个shell内建命令,不仅仅处理Linux信号还能对脚本退出(EXIT)、调试(DEBUG)、错误(ERR)、返回(RETURN)等情况指定处理方式,等同于现实世界的红绿灯信号。

原来在shell中总是用数字来代表信号,而在实际开发中为了体现专业性应该使用信号的名字;

  • 比如按Ctrl C会使脚本终止执行,实际上系统发送了SIGINT信号给脚本进程,SIGINT信号的默认处理方式就是退出程序。
  • 如果要在Ctrl C不退出程序,那么就得使用trap命令来指定一下SIGINT的处理方式了
  • 信号组合键Ctrl C组合键会产生SIGINT信号,Ctrl Z会产生SIGTSTP信号。

语法参数:

代码语言:javascript复制
用法:trap [-lp] [[参数] 信号声明 ...]
-p #把所有信号打印出来
-l #把所有信号打印出来

Linux信号常见信号:

代码语言:javascript复制
$trap -l #把所有信号打印出来。

信号 值 描述
1 SIGHUP 挂起进程
2 SIGINT 终止进程,通常使用Ctrl C来触发
3 SIGQUIT 停止进程,通常使用trl /来触发
6 SIGABRT 中止进程,通常因为某些验证的执行错误而引发
9 SIGKILL 无条件终止进程
14 SIGALRM 报警,通常用来处理超时信号
15 SIGTERM 尽可能终止进程,通常在系统关键时候发送
17 SIGSTOP 无条件停止进程,但不是终止进程
18 SIGTSTP 停止或暂停进程,但不终止进程
19 SIGCONT 继续运行停止的进程
20 SIGTSFP 停止进程运行但是该信号可以被处理或者被忽略,用户键入susp字符时(通常是Ctrl Z)发出这个信号

#全部信号
1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP
 6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1
11) SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR
31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN 1  36) SIGRTMIN 2  37) SIGRTMIN 3
38) SIGRTMIN 4  39) SIGRTMIN 5  40) SIGRTMIN 6  41) SIGRTMIN 7  42) SIGRTMIN 8
43) SIGRTMIN 9  44) SIGRTMIN 10 45) SIGRTMIN 11 46) SIGRTMIN 12 47) SIGRTMIN 13
48) SIGRTMIN 14 49) SIGRTMIN 15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX

实际案例:

代码语言:javascript复制
#忽略信号signals,可以同时指定多个信号
格式:trap "" signals
trap "" INT #表明忽略SIGINT信号,按Ctrl C也不能使脚本退出
trap "" HUP #表明忽略SIGHUP信号,即网络断开时也不能使脚本退出。
trap "echo $$" 1 2 3 15 20


#当shell接收到signals指定的信号时,执行commands命令
格式:trap "commands" EXIT #脚本退出时执行commands指定的命令
格式:trap "commands" DEBUG #在脚本执行时打印调试信息,比如打印将要执行的命令及参数列表
格式:trap "commands" ERR  #当命令出错,退出码非0,执行commands指定的命令。
格式:trap "commands" ERR  #当命令出错,退出码非0,执行commands指定的命令
trap "commands" signals  #重点


#把当前的trap设置打印出来
trap -p #显示
trap -p signal #设置 

#删除捕获令形式
格式: trap -- ***
trap -- SIGINT
trap -- 1 2 3 15 20

基础实例:

代码语言:javascript复制
#使用案例1:
trap "echo  Ctrl C 按下" INT
trap -p #trap -p INT
#trap -- 'echo  Ctrl C 按下' SIGINT
[root@master bash-5.0]# ^CCtrl C 按下


#实际案例2:Trap终止信号捕获(可直接调用函数)
trap "Global_TrapSigExit_Sig1" 1
trap "Global_TrapSigExit_Sig2" 2
# Trap终止信号1 - 处理
Global_TrapSigExit_Sig1() {
    echo -e "nn${Msg_Error}Caught Signal SIGHUP, Exiting ...n"
    exit 1
}
# Trap终止信号2 - 处理 (Ctrl C)
Global_TrapSigExit_Sig2() {
    echo -e "nn${Msg_Error}Caught Signal SIGINT (or Ctrl C), Exiting ...n"
    exit 1
}

shell脚本案例:

代码语言:javascript复制
#!/bin/bash
# test trap command
trap "echo 'Sorry! I have trapped Ctrl-C'" SIGINT #关键点

echo This is a test script

count=1
while [ $count -le 10 ]
do
  echo "Loop $count"
  sleep 1
  count=$[ $count   1 ]
done

echo The end.

#运行结果:
This is a test script
Loop 1
Loop 2
^CSorry! I have trapped Ctrl-C  #关键点-按照输出定义的退出操作
Loop 3
Loop 4
^CSorry! I have trapped Ctrl-C
Loop 5
Loop 6
Loop 7
Loop 8
^CSorry! I have trapped Ctrl-C
Loop 9
Loop 10
The end.


#示例2.INT信号当我们CTRL C执行触发该信号则清理文件
trap "find /tmp -type -f -name 'weiyi_' | xargs rm -f && exit" INT 
while true
do
    touch /tmp/weiyi_$(date  %F-%T)
    usleep 5000 # 5000微秒us
done

除了在shell脚本中捕获信号外,也可以在shell退出时捕获,在trap命令后加上EXIT信号就行。

代码语言:javascript复制
#!/bin/bash
# test trap command
trap "echo Goodbye." EXIT  #关键点值得学习

echo This is a test script

count=1
while [ $count -le 10 ]
do
  echo "Loop $count"
  sleep 1
  count=$[ $count   1 ]
done

echo The end.

#执行结果
This is a test script.
........
The end.
Goodbye.  #关键点

高级使用trap与跳板机进行联用:

代码语言:javascript复制
#shell跳板机(触发信号后屏蔽信号) - weiyigeek.sh
#!/bin/bash
#Linux中shell信号处理
function trapper()
{
    trap '' INT QUIT TSTP TERM HUP
}

#Linux中菜单设置
function menu(){
cat <<-EOF
################ HOST list ###############
    1) Localhost
    2) 192.168.1.1
    3) 10.10.107.221
    4) exit
################ HOST list ###############
EOF
}

#输入选择
function host(){
    case $1 in
        1) ssh -p22 $USER@localhost ;;
        2) ssh -p3125 root@192.168.1.1 ;;
        3) ssh -p22 root@10.10.107.221 ;;
        4|*) echo "退出SHELL";exit ;;
    esac
}

function main() {
    while :
    do
        trapper
        clear
        menu
        read -p "Please slect:" num
        host $num
    done
}
main

##配置启动调用文件
##cat /etc/profile.d/login.sh
[ $UID -ne 0 ] && [$UID -ne 500 ] && 。 /opt/weiyigeek.sh

WeiyiGeek.shell跳板机

补充知识点:

  • 在/etc/profile.d/目录中存放的脚本会在您登录shell的时候自动执行

0x04 命令行帮助
complete 命令

描述:该命令是bash shell的一个内建命令,使用 man complete 或 man bash 可以查看其帮助.

该命令的作用就是规定参数如何自动补全包括:

  • Path-name completion 路径名的补全
  • File-name completion 文件名的补全
  • User-name completion 用户名的补全
  • Host-name completion 主机名的补全
  • Variable-name completion 变量名的补全

基础语法:

代码语言:javascript复制
# 语法
complete [-abcdefgjksuv] [-pr] [-DE] [-o 选项] [-A 动作] [-G 全局模式] [-W 词语列表]  [-F 函数] [-C 命令] [-X 过滤模式] [-P 前缀] [-S 后缀] [名称 ...]
# 其他选项(如果指定)具有以下含义应该引用-G、-W和-X选项的参数(如果必要,还可以引用-P和-S选项),以防止在调用完整的内建程序之前扩展它们。

# 参数
"-o bashdefault":如果没有生成补全条目,就使用bash默认的其它补全。
"-o default":如果没有生成补全条目,就使用"readline"默认的文件名补全。
"-o dirnames":如果没有生成补全条目,就进行目录名补全。
"-o filenames":告诉"readline"生成文件名,以便进行与文件名相关的处理,例如在目录名后面加上斜杠,引用特殊字符,去掉行尾的空格,目的是用于shell函数。
"-o noquote":告诉"readline"不引用文件名,默认会进行引用。
"-o nospace":告诉"readline"在补全的名称后不添加空格,默认添加空格。
"-o plusdirs":生成补全条目之后,还会进行目录名补全并把结果添加到其它动作得到的结果中。

"-A alias":别名,同选项"-a"。
"-A arrayvar":数组变量名。
"-A binding":"readline"键绑定名。
"-A builtin":shell内建命令名,同选项"-b"。
"-A command":命令名,同选项"-c"。
"-A directory":目录名,同选项"-d"。
"-A disabled":不可用的shell内建命令名。
"-A enabled":可用的shell内建命令名。
"-A export":导出的shell变量名,同选项"-e"。
"-A file":文件名,同选项"-f"。
"-A function":shell函数名。
"-A group":组名,同选项"-g"。
"-A helptopic":内建命令help支持的帮助主题。
"-A hostname":主机名,从shell环境变量HOSTFILE中获取。
"-A job":作业名,同选项"-j"。
"-A keyword":shell保留字,同选项"-k"。
"-A running":正在运行的作业名。
"-A service":服务名,同选项"-s"。
"-A setopt":内建命令set的选项"-o"可用的参数。
"-A shopt":内建命令shopt可接受的选项名。
"-A signal":信号名。
"-A stopped":暂停的作业名。
"-A user":用户名,同选项"-u"。
"-A variable":所有的shell变量名,同选项"-v"。

"-C command":在子shell中执行命令,并把其结果作为补全条目。

"-F function":在当前的shell环境中执行函数function,执行时,参数"$1"表示那个参数正在进行补全的命令名,参数"$2"表示补全的名称,参数"$3"表示补全的名称前面的单词,表示结束执行时从数组变量COMPREPLY中获取补全条目。

"-G globpat":使用文件名扩展模式globpat进行扩展以生成可能的补全条目。
"-P prefix":在所有的选项应用到补全结果后,在结果前添加前缀prefix。
"-S suffix":在所有的选项应用到补全结果后,在结果后添加后缀suffix。
"-W wordlist":使用特殊变量IFS中的字符拆分单词列表wordlist,并扩展拆分后的每个单词,结果中与待补全单词
匹配的条目就是补全条目。
"-X filterpat":filterpat是进行文件名扩展时使用的模式,它作用于通过前面的选项和参数生成的补全列表,并把每个与过滤模式匹配的条目删除,模式中前导的叹号表示否定,这时会删除与过滤模式不匹配的条目。

基础实例:

代码语言:javascript复制
#示例1.实现sudo自动补齐
complete -c sudo #临时生效
cat >> ~/.bashrc <<'END'
complete -c sudo
END

[root@node2 ~]# complete -c sudo
[root@node2 ~]# sudo
Display all 1563 possibilities? (y or n)


#示例2.函数绑定
cat > /etc/bash_completion.d/Testcmd<<'end'
# Completion
_Testcmd(){
   local cur opts
   #1.数组变量(包含当前命令行中每个单独的子),其中COMP-CWORD 表示当前光标位置在${COMP_WORDS} 中的索引;
   cur="${COMP_WORDS[COMP-CWORD]}"
   #2.命令选项
   opts="--help --version"

   if [[ ${cur} == -* ]];then
      #3.生成可供补全的选项列表
      COMPREPLY=($(compgen -W "${opts}" -- ${cur}))
   fi
}
#4.补全函数绑定到具体的shell脚本中
complete -F _Testcmd Testcmd
end

0 人点赞