一文详解shell 脚本语言的基本结构,万字长文,建议收藏

2023-10-31

2.1 shell脚本的用途

  • 自动化常用命令
  • 执行系统管理和故障排除
  • 创建简单的应用程序
  • 处理文本或文件

2.2 shell脚本基本结构

shell脚本编程:是基于过程式、解释执行的语言

编程语言的基本结构:

  • 各种系统命令的组合
  • 数据存储:变量、数组
  • 表达式:a + b
  • 控制语句:if

shell脚本:包含一些命令或声明,并符合一定格式的文本文件

格式要求:首行shebang机制

#!/bin/bash
#!/usr/bin/python
#!/usr/bin/perl

2.3 创建shell脚本过程

第一步:使用文本编辑器来创建文本文件

第一行必须包括shell声明序列:#!

示例:

#!/bin/bash

添加注释,注释以#开头

第二步:加执行权限

给予执行权限,在命令行上指定脚本的绝对或相对路径

第三步:运行脚本

直接运行解释器,将脚本作为解释器程序的参数运行

2.4 脚本注释规范

  1. 第一行一般为调用使用的语言
  2. 程序名,避免更改文件名为无法找到正确的文件
  3. 版本号
  4. 更改后的时间
  5. 作者相关信息
  6. 该程序的作用,及注意事项
  7. 最后是各版本的更新简要说明

2.5 第一个脚本

#!SHEBANG
CONFIGURATION_VARIABLES
FUNCTION_DEFINITIONS
MAIN_CODE

shell脚本范例:

#!/bin/bash
# ------------------------------------------
# Filename: hello.sh
# Version:   1.1
# Date: 2017/06/01
# Author: wang
# Email: wang@gmail.com
# Website: www.magedu.com
# Description: This is the first script
# Copyright: 2017 wang
# License: GPL
# ------------------------------------------
echo “hello world”

范例:

#!/bin/bash
#
#********************************************************************
2.6 脚本调试
检测脚本中的语法错误
调试执行
2.7 变量
2.7.1 变量
变量表示命名的内存空间,将数据放在内存空间中,通过变量名引用,获取数据
2.7.2 变量类型
变量类型:
内置变量,如:PS1,PATH,HISTSIZE
用户自定义变量
不同的变量存放的数据不同,决定了以下
1. 数据存储方式
2. 参与的运算
3. 表示的数据范围
变量数据类型:
字符
数值:整型、浮点型,bash 不支持浮点数
2.7.3 编程语言分类
#Author: wangxiaochun
#QQ: 29308620
#Date: 2019-12-20
#FileName: backup.sh
#URL: http://www.magedu.com
#Description: The test script
#Copyright (C): 2019 All rights reserved
#********************************************************************
echo -e "\033[1;32mStarting backup...\033[0m"
sleep 2
cp -av /etc/ /data/etc`date +%F`/
echo -e "\033[1;32mBackup is finished\033[0m"

2.6 脚本调试

检测脚本中的语法错误

bash -n /path/to/some_script

调试执行

bash -x /path/to/some_script

2.7 变量

2.7.1 变量

变量表示命名的内存空间,将数据放在内存空间中,通过变量名引用,获取数据

2.7.2 变量类型

变量类型:

  • 内置变量,如:PS1,PATH,HISTSIZE
  • 用户自定义变量

不同的变量存放的数据不同,决定了以下

  1. 1数据存储方式
  2. 2参与的运算
  3. 表示的数据范围

变量数据类型:

  • 字符
  • 数值:整型、浮点型,bash 不支持浮点数

2.7.3 编程语言分类

一文详解shell 脚本语言的基本结构,万字长文,建议收藏

 

静态和动态语言

  • 静态编译语言:使用变量前,先声明变量类型,之后类型不能改变,在编译时检查,如:java,c
  • 动态编译语言:不用事先声明,可随时改变类型,如:bash,Python

强类型和弱类型语言

  • 强类型语言:不同类型数据操作,必须经过强制转换才同一类型才能运算,如java , c# ,python

如:以下python代码

print('magedu'+ 10) 提示出错,不会自动转换类型

print('magedu'+str(10)) 结果为magedu10,需要显示转换类型

  • 弱类型语言:语言的运行时会隐式做数据类型转换。无须指定类型,默认均为字符型;参与运算会自动进行隐式类型转换;变量无须事先定义可直接调用

如:bash ,php,javascript

2.7.4 Shell中变量命名法则

  • 不能使程序中的保留字:如:if, for
  • 只能使用数字、字母及下划线,且不能以数字开头,注意:不支持短横线 “ - ”
  • 见名知义,用英文名字,并体现出实际作用
  • 统一命名规则:驼峰命名法, studentname,大驼峰StudentName 小驼峰studentName
  • 变量名大写
  • 局部变量小写
  • 函数名小写

2.7.5 变量定义和引用

变量的生效范围等标准划分变量类型

  • 普通变量:生效范围为当前shell进程;对当前shell之外的其它shell进程,包括当前shell的子shell进程均无效
  • 环境变量:生效范围为当前shell进程及其子进程
  • 本地变量:生效范围为当前shell进程中某代码片断,通常指函数

变量赋值:

name='value'

value 可以是以下多种形式

直接字串:name='root'
变量引用:name="$USER"
命令引用:name=`COMMAND` 或者 name=$(COMMAND)

变量引用:

$name
${name}

弱引用和强引用

  • "$name " 弱引用,其中的变量引用会被替换为变量值
  • '$name ' 强引用,其中的变量引用不会被替换为变量值,而保持原字符串

显示已定义的所有变量:

set

删除变量:

unset name

范例:

[root@centos8 script40]#cat systeminfo.sh
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2019-12-23
#FileName: systeminfo.sh
#URL: http://www.magedu.com
#Description: Show system information
#Copyright (C): 2019 All rights reserved
#********************************************************************
COLOR="\033[1;31m"
END="\033[0m"
echo -e  "\033[1;32m-----------------Host systeminfo---------------$END"
echo -e  "HOSTNAME:     $COLOR`hostname`$END"
echo -e  "IPADDR:       $COLOR` ifconfig eth0|grep -Eo '([0-9]{1,3}\.){3}[0-9]
{1,3}' |head -n1`$END"
echo -e  "OSVERSION:    $COLOR`cat /etc/redhat-release`$END"
echo -e  "KERNEL:       $COLOR`uname -r`$END"
echo -e  "CPU:         $COLOR`lscpu|grep 'Model name'|tr -s ' '|cut -d : -
f2`$END"
echo -e  "MEMORY:       $COLOR`free -h|grep Mem|tr -s ' ' : |cut -d : -f2`$END"

练习

  • 1、编写脚本 systeminfo.sh,显示当前主机系统信息,包括:主机名,IPv4地址,操作系统版本,内核
  • 版本,CPU型号,内存大小,硬盘大小
  • 2、编写脚本 backup.sh,可实现每日将/etc/目录备份到/backup/etcYYYY-mm-dd中
  • 3、编写脚本 disk.sh,显示当前硬盘分区中空间利用率最大的值
  • 4、编写脚本 links.sh,显示正连接本主机的每个远程主机的IPv4地址和连接数,并按连接数从大到小排序

2.7.6 环境变量

变量声明和赋值:

export name=VALUE
declare -x name=VALUE

变量引用:

$name
${name}

显示所有环境变量:

env
printenv
export
declare -x

删除变量:

unset name

bash内建的环境变量

PATH
SHELL
USER
UID
HOME
PWD
SHLVL
LANG
MAIL
HOSTNAME
HISTSIZE
_   下划线 表示前一命令的最后一个参数

2.7.7 只读变量

只读变量:只能声明定义,但后续不能修改和删除

声明只读变量:

readonly name
declare  -r name

查看只读变量:

readonly [-p]
declare -r

2.7.8 位置变量

位置变量:在bash shell中内置的变量, 在脚本代码中调用通过命令行传递给脚本的参数

$1, $2, ... 对应第1个、第2个等参数,shift [n]换位置
$0 命令本身,包括路径
$* 传递给脚本的所有参数,全部参数合为一个字符串
$@ 传递给脚本的所有参数,每个参数为独立字符串
$# 传递给脚本的参数的个数
注意:$@ $* 只在被双引号包起来的时候才会有差异

清空所有位置变量

set --

2.7.9 退出状态码变量

进程执行后,将使用变量 $? 保存状态码的相关数字,不同的值反应成功或失败,$?取值范例 0-255

$?的值为0 代表成功
$?的值是1到255   代表失败

范例:

ping -c1 -W1 hostdown &> /dev/null 
echo $?

用户可以在脚本中使用以下命令自定义退出状态码

exit [n]

注意:

脚本中一旦遇到exit命令,脚本会立即终止;终止退出状态取决于exit命令后面的数字

如果未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态码

2.7.10 展开命令行

展开命令执行顺序

把命令行分成单个命令词
展开别名
展开大括号的声明({})
展开波浪符声明(~)
命令替换$() 和 ``
再次把命令行分成命令词
展开文件通配(*、?、[abc]等等)
准备I/0重导向(<、>)
运行命令

防止扩展

反斜线(\)会使随后的字符按原意解释

范例:

echo Your cost: \$5.00 
Your cost: $5.00

加引号来防止扩展

单引号(’’)防止所有扩展
双引号(”“)也可防止扩展,但是以下情况例外:$(美元符号)

变量扩展

`` : 反引号,命令替换
\:反斜线,禁止单个字符扩展
!:叹号,历史命令替换

2.7.11 脚本安全和set

set 命令:可以用来定制shell环境

$- 变量

h:hashall,打开选项后,Shell 会将命令所在的路径hash下来,避免每次都要查询。通过set +h将h选项关闭

i:interactive-comments,包含这个选项说明当前的 shell 是一个交互式的 shell。所谓的交互式shell,在脚本中,i选项是关闭的

m:monitor,打开监控模式,就可以通过Job control来控制进程的停止、继续,后台或者前台执行等

B:braceexpand,大括号扩展

H:history,H选项打开,可以展开历史列表中的命令,可以通过!感叹号来完成,例如“!!”返回上最近的一个历史命令,“!n”返回第 n 个历史命令

set 命令实现脚本安全

-u 在扩展一个没有设置的变量时,显示错误信息, 等同set -o nounset

-e 如果一个命令返回一个非0退出状态值(失败)就退出, 等同set -o errexit

-o option 显示,打开或者关闭选项

显示选项:set -o

打开选项:set -o 选项

关闭选项:set +o 选项

-x 当执行命令时,打印命令及其参数,类似 bash -x

范例:

[root@centos8 ~]#set -o
allexport     off
braceexpand   on
emacs         on
errexit       off
errtrace       off
functrace     off
hashall       on
histexpand     on
history       on
ignoreeof     off
interactive-comments on
keyword       off
monitor       on
noclobber     off
noexec         off
noglob         off
nolog         off
notify         off
nounset       off
onecmd         off
physical       off
pipefail       off
posix         off
privileged     off
verbose       off
vi             off
xtrace         off

2.8 格式化输出printf

格式

printf "指定的格式" "文本1" ”文本2“……

一文详解shell 脚本语言的基本结构,万字长文,建议收藏

 

常用格式替换符

一文详解shell 脚本语言的基本结构,万字长文,建议收藏

 

说明:%s 中的数字代表此替换符中的输出字符宽度,不足补空格,默认是右对齐,%-10s表示10个字符宽,- 表示左对齐

常用转义字符

一文详解shell 脚本语言的基本结构,万字长文,建议收藏

 

范例:

[root@centos8 ~]#printf "%s\n" 1 2 3 4
1234
[root@centos8 ~]#printf "%f\n" 1 2 3 4
1.000000
2.000000
3.000000
4.000000
#.2f 表示保留两位小数
[root@centos8 ~]#printf "%.2f\n" 1 2 3 4
1.00
2.00
3.00
4.00
[root@centos8 ~]#printf "(%s)" 1 2 3 4;echo ""
(1)(2)(3)(4)
[root@centos8 ~]#printf " (%s) " 1 2 3 4;echo ""
 (1) (2) (3) (4) 
[root@centos8 ~]#printf "%s %s\n" 1 2 3 4
1 2 3 4
[root@centos8 ~]#printf "%s %s %s\n" 1 2 3 4
1 2 3 4  
#%-10s 表示宽度10个字符,左对齐
[root@centos8 ~]#printf "%-10s %-10s %-4s %s \n" 姓名 性别 年龄 体重 小明 男 20 70 
小红 女 18 50
姓名     性别     年龄   体重
小明     男        20   70
小红     女        18   50
#将十进制的17转换成16进制数
[root@centos8 ~]#printf "%X" 17
11[root@centos8 ~]# #将十六进制C转换成十进制
[root@centos8 ~]#printf "%d\n" 0xC
12
[root@centos8 ~]#VAR="welcome to Magedu";printf "\033[31m%s\033[0m\n" $VAR
welcome
to
Magedu
[root@centos8 ~]#VAR="welcome to Magedu";printf "\033[31m%s\033[0m\n" "$VAR"
welcome to Magedu
[root@centos8 ~]#

2.9 算数运算

bash中的算术运算:

+, -, *, /, %取模(取余), **(乘方)

乘法符号有些场景中需要转义

实现算术运算:

(1) let var=算术表达式
(2) var=$[算术表达式]
(3) var=$((算术表达式))
(4) var=$(expr arg1 arg2 arg3 ...)
(5) declare –i var = 数值
(6) echo ‘算术表达式’ | bc

内建的随机数生成器变量:

$RANDOM   取值范围:0-32767

范例:

#生成 0 - 49 之间随机数
echo $[$RANDOM%50]
#随机字体颜色
[root@centos8 ~]#echo -e "\033[1;$[RANDOM%7+31]mmagedu\033[0m"
magedu

增强型赋值:

+= i+=10 相当于 i=i+10
-= i-=j   相当于 i=i-j
*=
/=
%=
++ i++,++i   相当于 i=i+1
-- i--,--i   相当于 i=i-1

格式:

let varOPERvalue

范例:

#自加3后自赋值
let count+=3
[root@centos8 ~]#i=10
[root@centos8 ~]#let i+=20 
[root@centos8 ~]#echo $i
30
[root@centos8 ~]#j=20
[root@centos8 ~]#let i*=j 
[root@centos8 ~]#echo $i
600

范例:

#自增,自减
let var+=1
let var++
let var-=1
let var--
[root@centos8 ~]#unset i j ; i=1; let j=i++; echo "i=$i,j=$j"
i=2,j=1
[root@centos8 ~]#unset i j ; i=1; let j=++i; echo "i=$i,j=$j"
i=2,j=2

2.10 逻辑运算

true, false

1, 0

与:&

1 与 1 = 1

1 与 0 = 0

0 与 1 = 0

0 与 0 = 0

或:|

1 或 1 = 1

1 或 0 = 1

0 或 1 = 1

0 或 0 = 0

非:!

! 1 = 0 ! true

! 0 = 1 ! false

异或:^

异或的两个值,相同为假,不同为真

范例:

[root@centos8 ~]#true 
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#false
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#! true
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#! false
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#x=10;y=20;temp=$x;x=$y;y=$temp;echo x=$x,y=$y
x=20,y=10
[root@centos8 ~]#x=10;y=20;x=$[x^y];y=$[x^y];x=$[x^y];echo x=$x,y=$y
x=20,y=10

短路运算

  • 短路与

CMD1 短路与 CMD2

第一个CMD1结果为 0 (假 ),总的结果必定为0,因此不需要执行CMD2

第一个CMD1结果为 1 (真),第二个CMD2必须要参与运算,才能得到最终的结果

  • 短路或

CMD1 短路或 CMD2

第一个CMD1结果为1 (真),总的结果必定为1,因此不需要执行CMD2

第一个CMD1结果为0 (假 ),第二个CMD2 必须要参与运算,,才能得到最终的结果

2.11 条件测试命令

条件测试:判断某需求是否满足,需要由测试机制来实现,专用的测试表达式需要由测试命令辅助完成测

试过程

评估布尔声明,以便用在条件性执行中

若真,则状态码变量 返 回 若 假 , 则 状 态 码 变 量? 返回1

条件测试命令

  • test EXPRESSION
  • [ EXPRESSION ]
  • [[ EXPRESSION ]]

注意:EXPRESSION前后必须有空白字符

-v VAR 变量VAR是否设置

示例:判断 NAME 变量是否定义

[ -v NAME ]

范例:

[root@centos8 ~]#unset x
[root@centos8 ~]#test -v x 
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#x=10
[root@centos8 ~]#test -v x 
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#y=""
[root@centos8 ~]#test -v y
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#[ -v y ]
[root@centos8 ~]#echo $?
0

2.11.2 数值测试

-gt 是否大于
-ge 是否大于等于
-eq 是否等于
-ne 是否不等于
-lt 是否小于
-le 是否小于等于

范例:

[root@centos8 ~]#i=10
[root@centos8 ~]#j=8
[root@centos8 ~]#[ $i -lt $j ] 
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#[ $i -gt $j ] 
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#[ i -gt j ] 
-bash: [: i: integer expression expected

2.11.3 字符串测试

-z "STRING" 字符串是否为空,空为真,不空为假
-n "STRING" 字符串是否不空,不空为真,空为假 
= 是否等于
!= 是否不等于
> ascii码是否大于ascii码
< 是否小于
== 左侧字符串是否和右侧的PATTERN相同
 注意:此表达式用于[[ ]]中,PATTERN为通配符
=~ 左侧字符串是否能够被右侧的PATTERN所匹配
 注意: 此表达式用于[[ ]]中;扩展的正则表达式

范例:

[root@centos8 ~]#unset str
[root@centos8 ~]#[ -z "$str" ]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#str=""
[root@centos8 ~]#[ -z "$str" ]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#str=" "
[root@centos8 ~]#[ -z "$str" ]
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#[ -n "$str" ]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#unset str
[root@centos8 ~]#[ -n "$str" ]
[root@centos8 ~]#echo $?
 1
[root@centos8 ~]#[ "$str" ]
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#str=magedu
[root@centos8 ~]#[ "$str" ]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#str=magedu
[root@centos8 ~]#[ "$str" ]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#str1=magedu
[root@centos8 ~]#str2=mage
[root@centos8 ~]#[ $str1 = $str2 ]
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#str2=magedu
[root@centos8 ~]#[ $str1 = $str2 ]
[root@centos8 ~]#echo $?
0

范例:

[root@centos8 ~]#FILE=test.log
[root@centos8 ~]#[[ "$FILE" == *.log ]]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#FILE=test.txt
[root@centos8 ~]#[[ "$FILE" == *.log ]]
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#[[ "$FILE" != *.log ]]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#[[ "$FILE" =~ \.log$ ]]
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#FILE=test.log
[root@centos8 ~]#[[ "$FILE" =~ \.log$ ]]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#N=100
[root@centos8 ~]#[[ "$N" =~ ^[0-9]+$ ]]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#N=A10
[root@centos8 ~]#[[ "$N" =~ ^[0-9]+$ ]]
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#IP=1.2.3.4
[root@centos8 ~]#[[ "$IP" =~ ^([0-9]{1,3}.){3}[0-9]{1,3}$ ]]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#IP=1.2.3.4567
[root@centos8 ~]#[[ "$IP" =~ ^([0-9]{1,3}.){3}[0-9]{1,3}$ ]]
[root@centos8 ~]#echo $?
1

2.11.4 文件测试

存在性测试

-a FILE:同 -e
-e FILE: 文件存在性测试,存在为真,否则为假
-b FILE:是否存在且为块设备文件
-c FILE:是否存在且为字符设备文件
-d FILE:是否存在且为目录文件
-f FILE:是否存在且为普通文件
-h FILE 或 -L FILE:存在且为符号链接文件
-p FILE:是否存在且为命名管道文件
-S FILE:是否存在且为套接字文件

范例:

[root@centos8 ~]#[ -d /etc ]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#[ -d /etc/issue ]
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#[ -L /bin ]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#[ -L /bin/ ]
[root@centos8 ~]#echo $?
1

文件权限测试:

-r FILE:是否存在且可读
-w FILE: 是否存在且可写
-x FILE: 是否存在且可执行
-u FILE:是否存在且拥有suid权限
-g FILE:是否存在且拥有sgid权限
-k FILE:是否存在且拥有sticky权限

范例:

[root@centos8 ~]#[ -w /etc/shadow ] 
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#[ -x /etc/shadow ] 
[root@centos8 ~]#echo $?
1

文件属性测试

-s FILE: 是否存在且非空
-t fd: fd 文件描述符是否在某终端已经打开
-N FILE:文件自从上一次被读取之后是否被修改过
-O FILE:当前有效用户是否为文件属主
-G FILE:当前有效用户是否为文件属组
FILE1 -ef FILE2: FILE1是否是FILE2的硬链接
FILE1 -nt FILE2: FILE1是否新于FILE2(mtime)
FILE1 -ot FILE2: FILE1是否旧于FILE2

2.12 关于()和{}

( list ) 会开启子shell,并且list中变量赋值及内部命令执行后,将不再影响后续的环境, 帮助参看:man bash搜索(list)

{ list; } 不会启子shell, 在当前shell中运行,会影响当前shell环境, 帮助参看:man bash 搜索{ list; }

范例: () 和 {}

[root@centos8 ~]#name=mage;(echo $name;name=wang;echo $name );echo $name
mage
wang
mage
[root@centos8 ~]#name=mage;{ echo $name;name=wang;echo $name; } ;echo $name
mage
wang
wang
[root@centos8 ~]#umask
0022
[root@centos8 ~]#(umask 066;touch f1.txt)
[root@centos8 ~]#ll f1.txt 
-rw------- 1 root root 0 Dec 23 16:58 f1.txt
[root@centos8 ~]#umask
0022
[root@centos8 ~]#( cd /data;ls )
test.log
[root@centos8 ~]#pwd
/root
[root@centos8 ~]#{ cd /data;ls; }
test.log
[root@centos8 data]#pwd
/data
[root@centos8 data]#

2.13 组合测试条件

第一种方式:

[ EXPRESSION1 -a EXPRESSION2 ] 并且
[ EXPRESSION1 -o EXPRESSION2 ] 或者
[ ! EXPRESSION ] 取反

说明: -a 和 -o 需要使用测试命令进行,[[ ]] 不支持

范例:

[root@centos8 ~]#ll /data/script40/test.sh
-rw-r--r-- 1 root root 382 Dec 23 09:32 /data/script40/test.sh
[root@centos8 ~]#[ -f $FILE -a -x $FILE ] 
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#chmod +x /data/script40/test.sh
[root@centos8 ~]#ll /data/script40/test.sh
-rwxr-xr-x 1 root root 382 Dec 23 09:32 /data/script40/test.sh
[root@centos8 ~]#[ -f $FILE -a -x $FILE ] 
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#chmod -x /data/script40/test.sh
[root@centos8 ~]#ll /data/script40/test.sh
-rw-r--r-- 1 root root 382 Dec 23 09:32 /data/script40/test.sh
[root@centos8 ~]#[ -f $FILE -o -x $FILE ] 
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#[ -x $FILE ] 
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#[ ! -x $FILE ] 
[root@centos8 ~]#echo $?
0

第二种方式:

一文详解shell 脚本语言的基本结构,万字长文,建议收藏

 

COMMAND1 && COMMAND2 并且,短路与,代表条件性的AND THEN
如果COMMAND1 成功,将执行COMMAND2,否则,将不执行COMMAND2
COMMAND1 || COMMAND2 或者,短路或,代表条件性的OR ELSE
如果COMMAND1 成功,将不执行COMMAND2,否则,将执行COMMAND2
! COMMAND   非,取反

一文详解shell 脚本语言的基本结构,万字长文,建议收藏

 

[root@centos7 ~]#[ $[RANDOM%6] -eq 0 ] && rm -rf /* || echo "click"
click

范例:

[root@centos8 ~]#id wang &> /dev/null ||   useradd wang
[root@centos8 ~]#id zhang &> /dev/null ||   useradd zhang
[root@centos8 ~]#getent passwd zhang
zhang:x:1002:1002::/home/zhang:/bin/bash
[root@centos8 ~]#[ -f “$FILE” ] && [[ “$FILE”=~ .*\.sh$ ]] && chmod +x $FILE
[root@centos8 ~]#grep -q no_such_user /etc/passwd || echo 'No such user'
No such user
[root@centos8 ~]#ping -c1 -W1 172.16.0.1 &> /dev/null && echo '172.16.0.1 is 
up' || (echo '172.16.0.1 is unreachable'; exit 1) 
172.16.0.1 is up
test "A" = "B" && echo "Strings are equal" 
test "A"-eq "B" && echo "Integers are equal"
[ "A" = "B" ] && echo "Strings are equal" 
[ "A" -eq "B" ] && echo "Integers are equal"
[ -f /bin/cat -a -x /bin/cat ] && cat /etc/fstab
[ -z "HOSTNAME" -o   HOSTNAME = "localhost.localdomain" ]&& hostname 
www.magedu.com

范例:

[root@centos8 ~]#cat /data/script40/ping.sh
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2019-12-23
#FileName: ping.sh
#URL: http://www.magedu.com
#Description: The test script
#Copyright (C): 2019 All rights reserved
#********************************************************************
IP=172.16.0.1
ping -c1 -W1 $IP &> /dev/null && echo "$IP is up" || {  echo "$IP is 
unreachable"; exit; }
echo "Script is finished"
[root@centos8 ~]#bash /data/script40/ping.sh
172.16.0.1 is up
Script is finished
[root@centos8 ~]#vim /data/script40/ping.sh
[root@centos8 ~]#cat /data/script40/ping.sh
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2019-12-23
#FileName: ping.sh
#URL: http://www.magedu.com
#Description: The test script
#Copyright (C): 2019 All rights reserved
#********************************************************************
IP=172.16.0.123
ping -c1 -W1 $IP &> /dev/null && echo "$IP is up" || {  echo "$IP is 
unreachable"; exit; }
echo "Script is finished"
[root@centos8 ~]#bash /data/script40/ping.sh
172.16.0.123 is unreachable

范例:

[root@centos8 ~]#cat /data/script40/disk_check.sh 
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2019-12-23
#FileName: disk_check.sh
#URL: http://www.magedu.com
#Description: The test script
#Copyright (C): 2019 All rights reserved
#********************************************************************
WARNING=80
SPACE_USED=`df|grep '^/dev/sd'|tr -s ' ' %|cut -d% -f5|sort -nr|head -1`
[ "$SPACE_USED" -ge $WARNING ] && echo "disk used is $SPACE_USED,will be full" 
| mail -s diskwaring root

练习

1、编写脚本 argsnum.sh,接受一个文件路径作为参数;如果参数个数小于1,则提示用户“至少应该给一个参数”,并立即退出;如果参数个数不小于1,则显示第一个参数所指向的文件中的空白行数

2、编写脚本 hostping.sh,接受一个主机的IPv4地址做为参数,测试是否可连通。如果能ping通,则提示用户“该IP地址可访问”;如果不可ping通,则提示用户“该IP地址不可访问”

3、编写脚本 checkdisk.sh,检查磁盘分区空间和inode使用率,如果超过80%,就发广播警告空间将满

4、编写脚本 per.sh,判断当前用户对指定参数文件,是否不可读并且不可写

5、编写脚本 excute.sh ,判断参数文件是否为sh后缀的普通文件,如果是,添加所有人可执行权限,否则提示用户非脚本文件

6、编写脚本 nologin.sh和 login.sh,实现禁止和允许普通用户登录系统

2.14 使用read命令来接受输入

使用read来把输入值分配给一个或多个shell变量,read从标准输入中读取值,给每个单词分配一个变量,所有剩余单词都被分配给最后一个变量

格式:

read [options] [name ...]

常见选项:

-p 指定要显示的提示

-s 静默输入,一般用于密码

-n N 指定输入的字符长度N

-d ‘字符’ 输入结束符

-t N TIMEOUT为N秒

范例:

[root@centos8 ~]#read 
wang
[root@centos8 ~]#echo $REPLY
wang
[root@centos8 ~]#read NAME TITLE
wang cto
[root@centos8 ~]#echo $NAME
wang
[root@centos8 ~]#echo $TITLE
cto
#Pipelines:A pipeline is a sequence of one or more commands separated by one of 
the control operators | or |&
[root@centos8 ~]#echo magedu | read NAME 
[root@centos8 ~]#echo $NAME
[root@centos8 ~]#echo magedu | { read NAME; echo $NAME; }
magedu
[root@centos8 ~]#read -p "Please input your name: " NAME
Please input your name: wang
[root@centos8 ~]#echo $NAME
wang

范例:

read -p “Enter a filename: “ FILE

范例:鸡兔同笼算法,今有雉兔同笼,上有三十五头,下有九十四足,问雉兔各几何?

[root@centos8 ~]#cat /data/script40/chook_rabbit.sh 
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2019-12-23
#FileName: chook_rabbit.sh
#URL: http://www.magedu.com
#Description: The test script
#Copyright (C): 2019 All rights reserved
#********************************************************************
read -p "请输入头的数量: " HEAD
read -p "请输入脚的数量: " FOOT
RABBIT=$[FOOT/2-HEAD]
CHOOK=$[HEAD-RABBIT]
echo "兔子: " $RABBIT
echo "鸡: " $CHOOK
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

一文详解shell 脚本语言的基本结构,万字长文,建议收藏 的相关文章

  • 在 Linux 中禁用历史记录 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 要在 Linux 环境中禁用历史记录 我执行了以下命令 export HISTFILESIZE 0 export HISTSIZE 0 u
  • awk: hping: 打印 icmp 发起/接收之间的差异

    我有以下输出hping http ports su net hping在 OpenBSD 上 hping icmp ts www openbsd org HPING www openbsd org re0 129 128 5 194 icm
  • 使用 find - 删除除任何一个之外的所有文件/目录(在 Linux 中)

    如果我们想删除我们使用的所有文件和目录 rm rf 但是 如果我希望一次性删除除一个特定文件之外的所有文件和目录怎么办 有什么命令可以做到这一点吗 rm rf 可以轻松地一次性删除 甚至可以删除我最喜欢的文件 目录 提前致谢 find ht
  • shell脚本中关联数组的时间复杂度

    我想知道在 shell 脚本中使用关联数组时如何构造 实现 另外 我想知道基于 shell 脚本的关联数组的时间复杂度是否是最佳的 因为我们可以使用字母和数字作为它们各自的键 编辑 他们使用什么哈希函数 如果您使用关联数组 则不能通过 使用
  • 使用 posix shell 测试字符串中的正则表达式

    如何测试字符串是否与特定字符串匹配正则表达式与基本 无 bash 或任何其他 posix shell 脚本 在 if 语句中 您可以使用expr在 POSIX shell 中计算正则表达式的命令 s Abc expr s alpha 3 e
  • git 别名中的 AWK 语句

    我正在尝试创建一个 git 别名来以特定格式打印日志中的所有拉取请求 但是 我在使用 AWK 删除双空格时遇到问题 这是使用以下命令的 git log 的输出 git log merges grep pull request pretty
  • 如何在 shell 脚本中并行运行多个实例以提高时间效率[重复]

    这个问题在这里已经有答案了 我正在使用 shell 脚本 它读取 16000 行的输入文件 运行该脚本需要8个多小时 我需要减少它 所以我将其划分为 8 个实例并读取数据 其中我使用 for 循环迭代 8 个文件 并在其中使用 while
  • 通过powershell运行ADB命令

    所以我尝试通过 powershell 脚本运行一些 ADB 命令 这是我正在尝试做的一个简单示例 adb shell echo in adb shell su root echo you are now root ls cd data da
  • 如何在数组中存储包含双引号的命令参数?

    我有一个 Bash 脚本 它生成 存储和修改数组中的值 这些值稍后用作命令的参数 对于 MCVE 我想到了任意命令bash c echo 0 0 echo 1 1 这解释了我的问题 我将用两个参数调用我的命令 option1 without
  • 添加要在给定命令中运行的 .env 变量

    我有一个 env 文件 其中包含如下变量 HELLO world SOMETHING nothing 前几天我发现了这个很棒的脚本 它将这些变量放入当前会话中 所以当我运行这样的东西时 cat env grep v xargs node t
  • 在 bash 脚本中提取 XML 值 [重复]

    这个问题在这里已经有答案了 我正在尝试从 xml 文档中提取一个值 该文档已作为变量读入我的脚本中 原始变量 data is
  • 符合 POSIX 标准的 shell 相当于 Bash“while read -d $'\0' ...”?

    我正在尝试使 Bash 脚本严格符合 POSIX 标准 即消除任何潜在的 Bashisms http mywiki wooledge org Bashism 通过使用checkbashisms px script filename 在给定的
  • 在退出脚本之前等待后台进程完成

    在退出脚本 TCL Bash 之前 如何确保所有后台进程已完成执行 我正在考虑将所有后台进程 pid 写入 pid 文件 然后最后 pgrep pidfile 以查看在退出之前是否有任何进程仍在运行 有一些更简单的方法可以做到这一点吗 TC
  • 每个命令都返回“bash:<命令>:找不到命令...”[关闭]

    Closed 这个问题是无法重现或由拼写错误引起 help closed questions 目前不接受答案 我刚刚安装了 Scala 并添加了路径gedit bashrc export SCALA HOME home avijit sca
  • GNU 并行与 rsync

    我正在尝试运行一些实例rsync并行使用ssh with GNU parallel 我正在运行的命令是这样的 find tmp tempfolder type f name chunck sort parallel gnu j 4 v ss
  • Bash 参数引号和 eval

    我编写了一个 bash 日志记录库 用我公司当前正在使用的一些复杂脚本来实现 在进行日志调用时 我一直致力于提供调用脚本的脚本文件名 BASH SOURCE 和行号 LINENO 但是 我不想依赖用户或实现脚本来将这两个变量作为参数传递 如
  • adb shell:无法使用 ESCAPE 键

    I want to use vi when running adb shell Starting vi is easy However I found that the ESC key doesn t seem to get through
  • 如何在 Makefile 中定义全局 shell 函数?

    我想定义一个shell函数 bin sh test do some complicated tests 1 2 if something then build thisway 1 2 else build otherway 1 2 fi 这
  • 为什么 shell=True 的 subprocess.Popen() 在 Linux 和 Windows 上的工作方式不同?

    使用时subprocess Popen args shell True 跑步 gcc version 仅作为示例 在 Windows 上我们得到 gt gt gt from subprocess import Popen gt gt gt
  • 如何在 Linux/OS X 上温和地终止 Firefox 进程

    我正在使用 Firefox 进行一些自动化操作 尽管我可以从 shell 打开 Firefox 窗口 但我无法正确终止它 如果我kill火狐进程与kill 3 or kill 2当我下次打开新的 Firefox 窗口时 命令会询问我是否要在

随机推荐

  • TCP和UDP详解

    本篇文章主要是从运输层协议概述 UDP TCP 可靠传输的工作原理 TCP首部格式 TCP可靠传输的实现 TCP流量控制 TCP的拥塞控制 TCP的连接管理这几个方面进行解析 不对之处还望指出 喜欢的可以点赞关注一下 谢谢 一 运输层协议概
  • 写一段js代码,完成字段校验规则:字段的长度必须介于6-20位之间,必须包含大小写字母和数字。...

    var regex new RegExp a z A Z 0 9 a zA Z0 9 6 20 if regex test fieldValue 校验通过 else 校验不通过
  • Dynamics 365 自动化发布工具Spkl介绍

    本篇主要是为了后面讲述CI CD时用到的工具做一个说明 先奉上spkl的github地址 没听说过的可以去查看下 挺不错的工具 我们主要用这个工具来部署WebResource Plugin和Workflow Activities 以及后续的
  • 一篇搞定SpringCloud面试(两万字)

    本文来自一位非常卷的在校学生写的学习笔记 哎 这样太卷了 作为一个苦逼的在读大学生 又要面临半年一度的期末考试了 因为上课没听 我啥都不会 什么通信原理 单片机 饶了我吧 给你们看看我上课在干啥你就知道我为啥啥都不会了 上课笔记 emmm
  • 群晖 NAS WebDAV服务手机ES文件浏览器远程访问【无公网IP内网穿透】

    iOS开发上架主页 在强者的眼中 没有最好 只有更好 我们是移动开发领域的优质创作者 同时也是阿里云专家博主 关注我们的主页 探索iOS开发的无限可能 我们与您分享最新的技术洞察和实战经验 助您在移动应用开发领域取得成功 欢迎访问我们的微信
  • 【YOLO v7】论文笔记

    YOLO v7 论文笔记 文章地址及源码 文章 https arxiv org abs 2207 02696 源码 https github com WongKinYiu yolov7 研究背景及主要贡献 针对目标群体 执行实时目标检测的计
  • docker安装seata1.5.2及其使用

    前言 最近进行了seata的安装和使用 对照网上的文章和文档进行安装配置使用的过程中绕了不少弯路 现在完成工作之后写一篇博文对此进行总结和记录 直接上案例 首先要注意Spring Cloud Alibaba Spring Cloud Spr
  • 了解并使用Xposed 框架神器

    什么是Xposed框架 Xposed 框架是个神器 帮助文档 关于Xposed框架的安装以及使用 https sspai com post 24538 Xposed下载地址以及模块库 https repo xposed info modul
  • 使用Qt Creator开发动态链接库,并在程序中调用(动态链接库)

    在 QT 中 一般将驱动 动态库 dll文件一概而论 一路下一步 至工程建立 dynamiclibrary h ifndef DYNAMICLIBRARY H define DYNAMICLIBRARY H include dynamicl
  • 以日期作为ts切片文件名问题的解决过程

    一 需求 EasyDarwin使用FFmpeg来保存流媒体 以多个ts分片形式存在 但由于EasyDarwin调用FFmpeg命令时 没有对生成名字做处理 所以默认生成的ts文件名都是out0 ts out1 ts 这种名称意义不大 需要以
  • 【华为OD机试真题 Java】最长连续子序列

    前言 本专栏将持续更新华为OD机试题目 并进行详细的分析与解答 包含完整的代码实现 希望可以帮助到正在努力的你 关于OD机试流程 面经 面试指导等 如有任何疑问 欢迎联系我 wechat steven moda email nansun09
  • 22款常用微信小程序UI框架推荐!

    22个好看 常用的微信小程序UI组件库推荐 1 WeUI 地址 https developers weixin qq com miniprogram dev extended weui 预览码 2 ColorUI 地址 https gith
  • flutter 数据持久化之sqflite

    sqflite 是一款轻量级的关系型数据库 类似SQLite 支持iOS和Android 适用于存储数据库 表类型的数据 使用 添加依赖 dependencies flutter sdk flutter sqflite插件 sqflite
  • html怎么在网页标题栏上添加图标

    需求 像下图这样给网页标题栏加个图标 方法 需要先把图片格式转换为 ico类型 在这个网址在线转换很方便 https www easyicon net covert 在加一行来显示图标 注意 如果加入了没有效果 检查一下路径是否正确 文件名
  • Linux安装rsync命令失败,rsync 常见错误与解决方法整理

    我们都是通过错误日志查看 在rsyncd log里面或 err文件里面 大家可以用记事本打开查看 注意windows下面我们需要给SvcwRsync用户 管理同步目录的所有权限 基本上这样就可以了 问题一 ERROR chroot fail
  • MySQL基本原理以及框架图

    数据库的定义 数据库简单来说是本身可视为电子化的文件柜 存储电子文件的所处 用户可以对文件 的数据运行新增 截取 更新 删除等操作 数据库指的是以一定的方式存储在一起 能为多个用户共享 具有尽可能小的冗余度 与应用程序彼此独立的数据集合 数
  • 反转链表:双指针法

    给你单链表的头节点 head 请你反转链表 并返回反转后的链表 指针 快慢指针 pre指向前一个节点 cur指向当前节点 temp用于保存当前节点的下一个节点 Definition for singly linked list public
  • Echarts柱状图设置柱间距不生效

    由于要做进度条样式的柱状图 如图所示 所以想做点柱子之间的间距 于是设置barGap代码配置如下 这里是错误示范 series name type bar data this downLoadChartsData seriesData ba
  • win10VirtualBox没有64位选项

    Windows10中Virtualbox没办法选择和安装64位的Linux系统 2017 03 08 十有三 0 浏览 5080 操作系统与应用 Windows系统 Linux 明明在公司的WIN7系统中使用Virtualbox就可以安装6
  • 一文详解shell 脚本语言的基本结构,万字长文,建议收藏

    2 1 shell脚本的用途 自动化常用命令 执行系统管理和故障排除 创建简单的应用程序 处理文本或文件 2 2 shell脚本基本结构 shell脚本编程 是基于过程式 解释执行的语言 编程语言的基本结构 各种系统命令的组合 数据存储 变