首页 > 系统相关 >linux之shell脚本quickStart

linux之shell脚本quickStart

时间:2023-08-19 14:55:13浏览次数:40  
标签:脚本 shell quickStart 空格 命令 linux 表达式 变量

这篇文章主要参考于《跟老男孩学linux运维:Shell编程实战》,方便写shell脚本时参考,只列一些shell脚本中的容易混淆的知识点。

目录

1 变量

变量就是用一个固定的字符串代替更多、更复杂的内容,使用变量的最大好处就是使程序开发更为方便。

1.1 普通变量

变量可分为全局变量和普通变量(局部变量),变量赋值时“=”两边不能加任何空格。

全局变量:可以在创建其shell脚本以及其派生出来的任意子进程shell脚本中使用。全局变量又分为自定义环境变量和bash内置的环境变量。

普通变量:只能在创建它们的shell函数或shell脚本中使用。

设置环境变量方法:

# 方法1:
export 变量名=value

# 方法2:
变量名=value

# 方法3:
declare -x 变量名=value

取消本地变量和环境变量:

unset # 使用unset消除本地变量和环境变量

查看环境变量:

# 方法1:
set # 命令输出所有变量,包括全局变量和局部变量、函数。
env # 命令只显示全局变量

变量赋值时要注意单引号,双引号的细微差别:

名称 说明
单引号 所见即所得,即输出时会将单引号内的所有内容原样输出,单引号看到是什么就是什么。
双引号 如果内容中有命令(要加反引号)、变量、特殊转义符等,会先将其解析,然后输出最终内容
无引号 赋值时,如果变量内容有空格,则会造成赋值不完整,如果内容中有命令(要加反引号),变量、特殊转义符等,会解析输出

建议:shell脚本中,字符串变量一定要加双引号,如果是数字可以不加

输出变量时,可以使用$c 和${c} 两种方法,而$(c) 有别的用途,如下:

把一个命令的结果作为变量的内容赋值:

# 方法1
变量名=`ls`  # 把命令用反引号引起来

# 方法2
变量名=$(ls) # 把命令用$()括起来,推荐这种方法

这一点与Makefile的方式并不相同,不要弄混了。

shell中变量引用与Makefile中的差别:

$x 单字符变量 $xx 或 $xxx_x多字符变量 $ $()
shell 变量取值 变量取值 变量取值 相当于``,解析命令结果
Makefile 变量取值 No 变量取值 变量取值

建议:Makefile中变量一定要写成$()或${}的形式,shell中使用$xx或${}的形式,shell中的$()另有用途。

1.2 shell特殊变量

在shell脚本中,存在一些特殊且重要的变量,例如:$0、$1、$#等。

位置变量 说明
$0 获取当前执行shell脚本的文件名(包括脚本路径)
$n 获取当前执行的shell脚本第n个参数值,n=1..9,当n=0时表示脚本的文件名,如果n>9,则用大括号括起来,如${10},接的参数以空格隔开
$# 获取当前执行的shell脚本后面接的参数总个数
$* 获取当前shell脚本所有传参的参数,不加引号和$@相同,如果给$*加上双引号,例如"$*",则表示将所有参数视为单个字符串,相当于"$1 $2 $3"
$@ 获取当前shell脚本所有传参的参数,不加引号和$*相同,如果给$@加上双引号,例如"$@",则表示将所有参数视为独立字符串,
相当于"$1" "$2" "$3", 这是将多参数传递给其它程序的最好方式,因为它会保留内嵌到参数里的空格。
$* 与 $@相同,但"$*" 与 "$@"两者有区别。
$? $?用于存储上一个命令的执行状态,它的取值范围通常为0-255,其中0表示执行成功,非0表示出现错误

1.3 shell特殊扩展变量

Shell的特殊扩展变量说明如下:

表达式 说明
VAL=$ 如果变量parameter没有定义或者值为空,则返回word字符串并替代变量的值,即VAL=word
用途:可以定义变量的默认值,这样如果变量未定义,则返回默认值
VAL=$ 如果变量parameter没有定义或者值为空,则设置这个变量值为word,并返回其值,
即parameter=word且VAL=word,基本同${parameter:-word},但该变量又额外给parameter变量赋值了
VAL=$ 如果变量parameter没有定义或者值为空,则返回word字符串作为标准错误输出,否则输出变量的值
用途:当变量parameter异常,报错并输出提醒。
VAL=$ 如果变量parameter没有定义或者值为空,则什么都不做,否则返回word字符串并替代变量的值。

在上述表达式内的冒号都是可选的。

2 运算符

2.1 空格

空格的注意事项:

在shell脚本中,空格的使用需要十分注意(不像C、Java等语言对空格不敏感)。

空格有如下注意事项:

  1. 定义变量时,=的两边不可以留空格,因为shell 会认为空格前的为一个命令,但是在()内部不限制,如for ((i= 1;i < 3;i= i+1))是正确的;

  2. (())内外部括号之间无空格,( () )这样报错。但内部括号内不限制,随便如s=$(( $i + 1 ))可以;

  3. 条件测试语句[ ] 的两边都要留空格;

  4. 条件测试的内容,如果是字符串比较的话, 比较符号两边要留空格;

  5. 操作符之间要用空格分开,如 test ! -d $1,其中的!和-d就要用空格分开,空格是命令解析中的重要分隔符;

  6. 命令和其后的参数或对象之间一定要有空格;

  7. 取变量值的符号'$'和后边的变量或括号不能有空格;

2.2 (()) 与 [ ]

(()) 与 [ ]用于条件表达式,区别见第4章,当然(())除了用于条件表达式外,还常用于算术数值运算。

2.3 || 与 &&

有时候,下一条命令依赖前一条命令是否执行成功。如:前一条命令成功执行之后再执行另一条命令,或者前一条命令执行失败后再执行另一条命令等。shell 提供了 && 和 || 来实现命令执行控制的功能,shell 将根据 && 或 || 前面命令的返回值来控制其后面命令的执行,这类似与C语言中的短路逻辑原则。

  1. 前一条命令成功执行之后再执行另一条命令 &&

    语法格式如下:

    command1 && command2 [&& command3 ...]
    

    只有在 && 左边的命令返回真,&& 右边的命令才会被执行。

  2. 前一条命令执行失败后再执行另一条命令 ||

    语法格式如下:

    command1 || command2 [|| command3 ...]
    

    只有在 || 左边的命令返回假,|| 右边的命令才会被执行。

3 常用命令

列出一些shell中常用的命令:

3.1 read

$ read -n2 -p 'please input you choice:\n' var 
-n2表示只接收2个字符,输入回车后,输入值保存到var变量中

3.2 echo

echo -e可以输出换行,可以解析转义字符。

$ echo -e 'aaa\nbbb' 输出:
aaa
bbb

3.3 eval

eval命令对变量进行两次扫描。

使用举例:

$ cat test
Hello World
$ myfile="cat test"
$ echo $myfile
cat test
$ eval $myfile
Hello World
# eval命令将会对该变量进行两次扫瞄。

3.4 双小括号(())

(())常用于整数运算中。shell中常见的算术运算命令如下:

其操作方法如下:

运算命令 意义
((i=i+1)) 此种书写为运算之后赋值,即将i+1的运算结果赋值给变量i
注意不能用echo ((i=i+1))来输出表达式的值,但可以用echo $((i=i+1))输出其值
i = $((i+1)) 可以在(())前加$符,表示将表达式运算后赋值给i
((8 > 7 && 5 == 5)) 可以进行比较操作以及逻辑操作
echo $((2+1)) 需要直接输入表达式的运算结果时,可以在(())前加$符

4 流程控制

4.1 条件表达式

条件表达式一般搭配&&与|| 来使用,进行一些简单的判断,或者搭配if语句来使用,实现一些较复杂的判断逻辑。

4.1.1 条件表达式几种形式

条件测试语法 说明
语法1: test <测试表达式> 利用test命令进行条件测试表达式的方法,test命令和<测试表达式>之间至少有一个空格
语法2:[ <测试表达式> ] 单中括号,和test命令的用法相同,[]的便捷和内容之间至少有一个空格
语法3:[[ <测试表达式> ]] 双中括号,是比test和[]更新的语法,支持通配符,双大括号里的两端也要有空格
语法4:((<测试表达式>)) 双小括号,一般用于if语句里,常用于计算,(())两端不需要有空格

4.1.2 文件测试表达式

常用的文件测试操作符 说明
-e 文件 exit,文件是否存在,区别与"-f"的是,-e不区分是文件夹还是目录
-d 文件 directory,文件存在且为文件夹则为真,即测试表达式成立
-f 文件 file,文件存在且为普通文件则为真,即测试表达式成立
-s 文件 size,文件存在且文件大小不为0则为真
-r 文件 read,文件存在且可读为真
-w 文件 write,文件存在且可写为真
-x 文件 executable, 文件存在且可执行则为真
f1 -nt f2,nt为newerthan newer than, 文件f1比文件f2新则为真,根据文件的修改时间来计算
f1 -ot f2,ot为olderthan older than, 文件f1比文件f2旧则为真,根据文件的修改时间来计算

4.1.3 字符串测试表达式

注意:

  1. 对于字符串的测试,一定要将字符串加双引号后再进行对比,这样避免字符串中有空格的情况;

  2. 比较符号(例如=和!=)的两端一定要有空格。

常用字符串测试操作符 说明
-n “字符串” 若字符串的长度不为0,则为真,即测试表达式成立,n可以理解为nozero
-z “字符串” 若字符串的长度为0,则为真,z可以理解为zero
“串1” = “串2” 若字符串1等于字符串2,则为真,可使用==代替=
“串1” != “串2” 若字符串1不等于字符串2,则为真

4.1.4 整数测试表达式

在[]以及test中使用的比较符号 在(())和[[]]中使用的比较符号 说明
-eq ==或= 相等,全拼为equal
-ne != 不相等,全拼为not equal
-gt > 大于,全拼为greater than
-ge >= 大于等于,全拼为greaterequal
-lt < 小于,全拼为less than
-le <= 小于等于,全拼为less equal

4.1.5 逻辑操作表达式

在[]中使用的逻辑操作符 在test、[[]]和(())中使用的逻辑操作符 说明
-a && and,与,两端都为真,则结果为真
-o ll or,或,两端有一个为真,则结果为真
not,非,两端相反,则结果为真

以下写法适用于所有条件表达式,是工作中比较常用的替代if语句的方法,以[]为例。

[ 条件1 ] && {
	命令1
	命令2
	命令3
}

# 等价于:
if [ 条件1 ]; then
	命令1
	命令2
	命令3
fi

# 同理:
[ 条件1 ] || {
	命令1
	命令2
	命令3
}

# 等价于:
if [ ! 条件1 ]; then
	命令1
	命令2
	命令3
fi

总结:

测试表达式 [] test [[]] (())
边界是否需要空格 需要 需要 需要(指内部[]) 不需要
文件测试表达式 -e、-d、-f 等 -e、-d、-f 等 -e、-d、-f 等 -e、-d、-f 等
字符串比较 =、==、!= =、==、!= =、==、!= =、==、!=
整数比较 -eq、-gt、-lt、-ge、-le -eq、-gt、-lt、-ge、-le -eq、-gt、-lt、-ge、-le 或
=、>、<、>=、<=
=、>、<、>=、<=
逻辑操作表达式 !、-a、-o !、-a、-o !、&&、|| !、&&、||
是否支持通配符 不支持 不支持 支持 不支持

4.2 if 语句

在所有编程语言里,if条件语句几乎是最简单、用途最广的语句格式。

一般的方式为:

# 第一种写法
if <条件表达式>
  then
  指令集1
fi

# 第二种写法,相当于换行
if <条件表达式>; then
  指令
fi

# 第三种写法:if else 结构
if <条件表达式>; then
  指令集1
else
  指令集2
fi

# 第四种写法:多分支结构 if-elif-else 结构,注意if与elif后都带有then,else后面没有then
if <条件表达式1>; then
  指令集1
elif <条件表达式2>; then
  指令集2
else
  指令集3
fi

4.3 case语句

case条件语句相当于多分支的if/elif/else条件语句,但是比条件语句看起来更工整,case语句比较适合变量值较少且为固定数字或字符串集合的情况。

如下:当变量的值等于1时,执行指令1,等于值2时执行指令2,依次类推,如果都不符合,则执行*)分支,此外,注意不同行内容的缩进距离。

case "变量" in
	值1)
		指令1...
		;;           # 双引号相当于c语言switch-case语句中的break
	值2)
		指令2...
		;;
	*)                # 相当于default分支,可以不用双引号;;
		指令3...
esac

4.4 循环结构

循环中常用的是while与for语句,区别是:while循环常用在守护进程,以及那些希望能持续执行不退出的应用。for循环语句主要用于执行次数有限的循环。

# 第一种写法:while循环语句
while <条件表达式>
do
  指令集1
done

# 第二种写法:until循环语句(使用的很少)
# 条件不成立进入循环,条件表达式成立时终止循环
until <条件表达式>
do
  指令集1
done

# 第三种写法:for循环语法结构
# 第一种for循环语句为变量取值型
for 变量名 in 变量取值列表
do
  指令集1
done

# 第二种for循环语句为C语言型for循环结构
for((exp1; exp2; exp3))
do
  指令集1
done

注意:sh并不支持第二种循环语句(C语言型for循环结构),见参考5

5 函数

5.1 shell函数的几种写法

# 第一种写法,function + 函数名 + 括号(推荐)
function 函数名() {
	指令...
	return n
}

# 以下两种方法都是简写,function和() 可以省略一个
# 第二种写法,函数名后无括号
function 函数名 {
	指令...
	return n
}

# 第三种写法,无function
函数名() {
	指令...
	return n
}

return与exit的用法:

return用来退出函数,exit用来退出脚本文件

5.2 shell函数的执行

shell函数执行的方式:

# 1. 函数不带参数时,直接调用函数名即可,也即function + 函数名 + 括号,只保留函数名即可
# 2. shell执行系统中各种程序的执行顺序为:系统别名->函数->系统命令->可执行文件
# 3. 函数需要先定义然后再执行函数,否则会报错
函数名

# 2. 带参数的函数执行方法
# 例如:函数名 $1 $2 $3
函数名 参数1 参数2

6 shell脚本的调试

有时shell脚本不正确,需要调试,可使用如下方法:

方法1:在脚本中加打印

在shell脚本中加echo

方法2:bash参数调试法

bash [-nvx] scripts.sh

其中:

-n :不会执行脚本,仅查询脚本语法是否有问题,并给出错误提示。

-v : 在执行脚本时,先将脚本内容输出到屏幕上,然后执行脚本,如果有错误,也会给出错误提示

-x :将执行的脚本内容及输出显示到屏幕上,这是对调试很有用

bash -x 的缺点: 当加载系统函数库等脚本时,有太多的输出,导致很难查看我们关注的内容,可以在脚本开始叫上set -x ,可以弥补bash -x的缺点,加了set -x后,就不需要用bash -x了。

方法3:线上语法检查工具

https://www.shellcheck.net/

注意:

shell脚本出错常与环境变量设置有关,这时候,可以使用 printenv 打印环境变量。或使用 export -p 命令显示全部拥有导出属性的变量。

7 shell脚本其它

7.1 shell脚本的执行方式

当shell脚本运行时,会先找茬系统环境变量ENV(加载顺序为:/etc/profile -> ~/.bash_profile -> ~/.bashrc->/etc/bashrc),在加载了环境变量文件后,Shell脚本开始执行Shell脚本的内容。

执行脚本有如下几种方式:

方式 说明
bash script-name 或 sh script-name 当脚本本身没有可执行权限时的使用方法,或脚本首行没有指定解释器(推荐)
./script-name 在当前路径下执行脚本,脚本需要有可执行权限
source script-name 或 . script-name 在当前父shell脚本中运行,(其它模式都会启动新进程执行子脚本)
source或者“ . ”相当于include功能,可以将脚本本身的变量值或函数传递到当前父shell脚本中使用。
sh < script-name 或 cat script-name | sh 用法不常见。

其中,source方法的特点是:

  1. 子shell脚本会直接继承父亲的shell脚本变量,函数(就像儿子随父亲姓,基因也继承父亲的),反之则不可以
  2. 如果希望父shell获得子shell脚本定义的变量,函数,需要使用source或. 在父shell脚本中先加载子shell脚本。

7.2 shell脚本开发规范

编程开发规范很重要,遵守规范,养成良好的编程习惯,可以大大提高开发效率,降低脚本维护成本。

# 规则1: shell脚本的第一行,通常用于指定脚本解释器,叫做解释伴随行( Shebang)
#!/bin/bash 或 #!/bin/sh

# 规则2:shell脚本中尽量不要用中文注释,应用英文注释,防止乱码

# 规则3:字符串赋值给变量应加双引号,并且等号前后不能有空格(shell脚本要注意空格的使用,见第二节,空格)

参考:

  1. shell脚本 空格
  2. shell 脚本里的 特殊字符 $(( ))、$( )、``与${ }的区别
  3. shell 中 &&和||的方法
  4. 【总结】超全shell条件测试命令及语法
  5. https://askubuntu.com/questions/400936/loop-variable-error-in-for-loop

标签:脚本,shell,quickStart,空格,命令,linux,表达式,变量
From: https://www.cnblogs.com/sureZ-learning/p/17642460.html

相关文章

  • linux云服务器状态上报
    统计某文件夹下文件的个数ls-l|grep “^-”|wc-l统计某文件夹下目录的个数ls-l|grep“^d”|wc-l统计文件夹下文件的个数,包括子文件夹里的。ls-lR|grep“^-”|wc-l统计文件夹下目录的个数,包括子文件夹里的。ls-lR|grep“^d”|wc-l说明:ls-l长列表输出该目录下文件信息(......
  • 部署Kafka+ZK及其日志采集实战(系统版本:linux_CentOs_7.8)
    部署ZKdockerrun-d--namezookeeper-p2181:2181-twurstmeister/zookeeper部署Kafka-p9092:9092\-eKAFKA_BROKER_ID=0\--envKAFKA_HEAP_OPTS=-Xmx256M\--envKAFKA_HEAP_OPTS=-Xms128M\-eKAFKA_ZOOKEEPER_CONNECT=[内网ip]:2181\-eKAFKA_ADVERTISED......
  • Linux 系统替换字符串常用命令
    概述在Linux系统中有时候我们需要替换某个很长的字符串或者修改某个配置参数,有些文件又隐藏目录比较深,有些场景也需要在一个目录下批量去修改文件,那应该怎么高效,快速的去完成修改呢?下面记录一下本人实施过程中的一些方法,做个备忘手稿分享以备随时查看。系统平台CentOSLinux7第......
  • Linux常用网络配置练习(2)
    打开第二台虚拟机(带图形界面的虚拟机)使用浏览器访问一些网站,然后统计这些连接处于time-wait的数量[[email protected]]#netstat-an|grepTIME_WAIT|wc-l14打开两台Linux虚拟机,然后测试它们之间的TCP性能和UDP性能,并将结果记录下来##虚拟机01[root@test-server......
  • dart集成shell脚本调用功能
    pubspec.yaml里添加依赖:shell:anyimport'dart:io';import'package:shell/shell.dart';voidmain(List<String>arguments)async{varshell=Shell();varpassword=Platform.environment['PASSWORD'];print('Passw......
  • linux下进程间通信
    进程间通信一、进程间通信的介绍1、进程间通信的概念进程通信(Interprocesscommunication),简称:IPC;本来进程之间是相互独立的。但是由于不同的进程之间可能要共享某些信息,所以就必须要有通讯来实现进程间的互斥和同步。比如说共享同一块内存、管道、消息队列、信号量等等就是实......
  • Xshell 连接本地虚拟机成功案例
    1、首先打开虚拟机,登录到操作系统;输入“ifconfig”,在弹出的一段中,inet地址就是本地虚拟机的ip地址。2、接着打开xshell软件如果没有可以到 http://www.linuxidc.com/Linux/2016-08/134086.htm 下载xshell点击“新建”按钮,或者用快捷键Alt+N,新建会话在会话中的主机中输入刚刚得到......
  • Linux命令
    常用命令命令ls-a这个选项能显示.开头的隐藏文件-i显示每个文件的inode号-m所有项目以逗号分隔,并填满整行行宽-R同时列出所有子目录层-h将列出文件的大小以人性化格式输出ls-lc[文件名]查看文件的访问时间ls-lu[文件名]查看文件的最后修改时间ls-l显示文件的......
  • linux下gcc/g++创建一个共享库项目以及创建一个可执行项目动态链接该共享库
    1.先确保有g++命令2.创建一个c++项目目录,并cd到该目录3.创建共享库头文件:dynamic_so.h#ifndef__TEST__#define__TEST__inttestFun(inta,intb);#endif4.创建对应共享库的实现文件:dynamic_so.cpp#include"dynamic_so.h"inttestFun(inta,intb){returna......
  • linux环境下基于python的OpenCV 保存视频
    一概念在OpenCV中保存视频使用的是VedioWriter对象,在其中指定输出文件的名称,A创建视频写入的对象out=cv2.VideoWriter(filename,fourcc,fps,frameSize)参数含义:filename:视频保存的位置fourcc:指定视频编解码器的4字节代码fps:帧率frameSize:帧大小B 设置视频的编解......