1. 多行注释

#!/bin/bash<< COMMENT
This is multi
line comment
COMMENTecho "This is demo script"

注意:

<<符号后面的关键词可以是任意字符串,但是前面使用什么关键词,结束注释时必须使用同样的关键词,如果使用 << ABC 开始注释,那么结束注释时必须使用 ABC,字母区分大小写。

2. 执行方式

默认情况下,创建脚本之后是无法直接运行的:

$ ./demo.sh
-bash: ./demo.sh: Permission denied

bash 或者 sh 这样的解释器,是可以将脚本文件作为参数来执行脚本文件的。

$ bash demo.sh
This is demo script
$ sh demo.sh
This is demo script

修改脚本具有可执行权限,然后就可以使用相对路径或者绝对路径来执行了。

$ chmod +x demo.sh
$ ./demo.sh
This is demo script
$ /home/wohu/Downloads/shell_demo/demo.sh
This is demo script
$

2.1 开启子进程

输入 pstree,可以看到

$ pstree
systemd─┬─ModemManager───2*[{ModemManager}]├─NetworkManager─┬─dhclient│                └─2*[{NetworkManager}]
...├─sshd─┬─2*[sshd───sshd───bash]│      ├─sshd───sshd───bash───pstree│      ├─sshd───sshd───sftp-server│      └─sshd───sshd───bash───ssh
...

可以看到系统启动的第一个进程是 systemd,其它进程都是这个进程的子进程,不管是直接执行脚本,还是通过 bash 或者 sh 这样的解释器执行脚本,都是会开启子进程的,下面验证一下,

创建下面的文件内容并通过 ./sleep.sh 执行该脚本文件

$ cat sleep.sh
#!/bin/bash
sleep 100

然后输入 pstree 可以看到

├─sshd─┬─2*[sshd───sshd───bash]│      ├─sshd───sshd───bash───sleep.sh───sleep│      ├─2*[sshd───sshd───sftp-server]│      ├─sshd───sshd───bash───pstree│      └─sshd───sshd───bash───ssh

bash 终端下开启了一个子进程脚本文件 sleep.sh,通过该脚本文件执行了一条 sleep 命令。

另外一种方法,使用 bash sleep.sh执行,然后输入 pstree 可以看到

        ├─sshd─┬─2*[sshd───sshd───bash]│      ├─sshd───sshd───bash───bash───sleep│      ├─2*[sshd───sshd───sftp-server]│      ├─sshd───sshd───bash───pstree│      └─sshd───sshd───bash───ssh

bash 进程下开启了一个子进程 bash,在 bash 子进程中执行了一条 sleep 命令。

2.2 不开启子进程

打开终端使用 source 或者 . 来执行脚本文件

$ source  sleep.sh

或者

. sleep.sh

另外开个终端,然后输入 pstree 可以看到

        ├─sshd─┬─2*[sshd───sshd───bash]│      ├─sshd───sshd───bash───sleep│      ├─2*[sshd───sshd───sftp-server]│      ├─sshd───sshd───bash───pstree│      └─sshd───sshd───bash───ssh

脚本文件中的 sleep 命令是直接在 bash 终端下执行的。

特殊的文件命令如下

$ cat exit.sh
#!/bin/bash
exit

分别使用开启子进程和不开启子进程的方式执行,

$ source exit.sh
$ bash exit.sh

可以发现:

  • source 命令不开启子进程执行脚本文件会导致整个终端被关闭;
  • bash 命令开启子进程执行脚本文件却不受影响;

3. 数据输入和输出

3.1 使用 echo 命令输出

echo 命令可以实现任意字符串消息的输出,可以使用多个 echo 输出多条消息,也可以使用一个 echo 命令,将多条信息用引号 "" 包含一起输出。

$ cat demo.sh
#!/bin/bashecho "one"
echo "two"
echo "This is
demo script"

echo 命令支持 -e 选项,该选项可以让 echo 命令识别 \ 后面的转义符含义,常见的转义符见下表:

注意: -e 选项和后面的输出内容至少要有一个空格。

echo -e "\033[1mok\033[0m"

\033 或者 \e 后面跟不同的代码可以设置不同的终端属性,如 1m 是让终端粗体显示字符串、后面的 OK 就是需要显示的字符串内容,最后的 \033[0m 是在终端加粗显示字符串后,关闭终端的属性设置,如果没有使用 0m 关闭属性设置,则之后终端所有字符串都用粗体显示。


使用示例:

#!/bin/bash
#Version:2.0
clear
echo -e "\033[42m---------------------------------\033[0m"
echo -e "\e[2;10H这里是菜单\t\t#"
echo -e "#\e[32m 1.查看网卡信息\e[0m                #"
echo -e "#\e[33m 2.查看内存信息\e[0m                #"
echo -e "#\e[34m 3.查看磁盘信息\e[0m                #"
echo -e "#\e[35m 4.查看CPU信息\e[0m                 #"
echo -e "#\e[36m 5.查看账户信息\e[0m                #"
echo -e "\033[42m---------------------------------\033[0m"
echo

3.2 使用 read 命令读取

read命令语法如下:

read [选项] [变量名]

如果未指定变量名,则变量名默认为 REPLY


4. 输入输出重定向

Linux 系统输出可以分为标准输出和标准错误输出。

  • 标准输出的文件描述符为 1
  • 标准错误输出的文件描述符为 2
  • 标准输入的文件描述符为 0

可以使用 > 或者 >> 符号将输出信息重定向到文件中。

  • > 符号将输出信息重定向到文件,如果文件不存在,则系统会自动创建该文件,如果文件已经存在,则系统会将文件的所有内容覆盖;
  • >> 符号将输出信息重定向到文件,如果文件不存在,则系统会自动创建该文件,如果文件已经存在,则系统会将输出的信息追加到该文件原有信息的末尾;

使用 1 > 或者 1 >> 可以将标准输出信息重定向到文件 (1 可以忽略不写,默认值就是 1)。可以使用 2 > 或者 2 >> 将错误的输出信息重定向到该文件。






使用 << 符号可以将数据内容重定向传递给前面的一个命令,作为命令的输入。<< 符号代表需要的内容在这里。

[wohu@bogon Videos]$ cat >  demo.sh << EOF
this is demo
EOF
[wohu@bogon Videos]$ cat demo.sh
this is demo
[wohu@bogon Videos]$
[wohu@bogon Videos]$ cat >  demo.sh << HERE
this is test script
HERE
[wohu@bogon Videos]$ cat demo.sh
this is test script
[wohu@bogon Videos]$

5. 各种引号的使用

5.1 单双引号

$ touch a b c          # 创建三个文件,分别为 a b c
$ touch "a b c"       # 创建一个文件,空格为文件名的一部分

双引号的作用是引用一个整体,计算机会把整个引号内的内容当做一个整体来看待。

Linux系统中,除了可以使用一个双引号引用一个整体,也可以使用单引号引用一个整体,同时单引号还有另外一个功能是将特殊字符含义屏蔽,转化为字符表面的含义。

$ touch 'a b c'
$ echo ############

本来想输出一个 #符号,但实际输出的是一个空白行,因为 #符号及其后面的内容会被理解为注释而不会执行,所以要想输出 #符号,可以使用单引号 '###'

$ echo '########'

Shell$符号具有提取变量值的特殊含义,当需要显示 $符号时,也需要使用单引号屏蔽功能。

wohu@wohu-pc:~$ test=19
wohu@wohu-pc:~$ echo "$test"
19
wohu@wohu-pc:~$ echo '$test'
$test
wohu@wohu-pc:~$

5.2 命令替换

反引号 ` 是一个命令替换符号,它可以使用命令的替换结果替代命令。

wohu@wohu-pc:~$ echo `date +%Y-%m-%d`
2022-07-27
wohu@wohu-pc:~$
wohu@wohu-pc:~$ echo `ls | wc -l`
16
wohu@wohu-pc:~$

反引号容易跟单引号混淆,并且不支持嵌套,所以又有了 $()组合命令,同样用于命令替换。

wohu@wohu-pc:~$ echo $(pwd)
/home/weirong
wohu@wohu-pc:~$ echo $(ls | wc -l)
16
wohu@wohu-pc:~$ echo $(date +%Y-%m-%d)
2022-07-27
wohu@wohu-pc:~$

6. 变量

变量名由数字、字母、下划线组成,且开头不能以数字开头,定义变量时等号两边不可以有空格。
当需要读取变量时,需要在变量名前加一个 $符号,且变量名与其它非变量名混在一起时,需要使用 {}分隔。

wohu@wohu-pc:~$ a = 123
a: command not found
wohu@wohu-pc:~$ a=123
wohu@wohu-pc:~$ echo $a
123
wohu@wohu-pc:~$ echo $(a)   # $() 用于命令替换
a: command not foundwohu@wohu-pc:~$ echo ${a}      # ${} 用于引用变量
123
wohu@wohu-pc:~$ echo $aappleswohu@wohu-pc:~$ echo ${a}apples
123apples
wohu@wohu-pc:~$

脚本

#!/bin/bash
#描述信息:本脚本主要目的是获取主机的数据信息(内存、网卡IP、CPU负载)localip=$(ifconfig eth0 | grep netmask | tr -s " " | cut -d" " -f3)
mem=$(free |grep Mem |tr -s " " | cut -d" " -f7)
cpu=$(uptime | tr -s " " | cut -d" " -f13)
echo "本机IP地址是:$localip"
echo "本机内存剩余容量为:$mem"
echo "本机CPU 15分钟的平均负载为:$cpu"
  • tr -s " " 将多个空格合并为一个
  • cut -d" " -f3以空格分列,并输出第三列

常见系统预设变量有:

7. 数据过滤与正则表达

grep [选项] 匹配模式 [文件]
  • -i 忽略字母大小写
  • -v 取反匹配
  • -w 匹配单词

8. 算术运算

Shell支持多种算术运算,可以使用 $((表达式))$[表达式]let 表达式 进行整数算术运算,使用 bc 命令进行小数运算。

wohu@wohu-pc:~$ echo $((3+4))
7
wohu@wohu-pc:~$ echo $[3+4]
7
wohu@wohu-pc:~$ a=3
wohu@wohu-pc:~$ echo $[a++]
3
wohu@wohu-pc:~$ echo $[a++]
4
wohu@wohu-pc:~$ echo $[++a]
6
wohu@wohu-pc:~$

运算符号见下表:

9. 一行多条命令

一行代码中输入多行 shell 命令,可以用分号 ;,与号 && ,或 || 将多个命令分开。

  • cmd1 ; cmd2 先执行 cmd1,再执行 cmd2,不管 cmd1 执行结果如何,整个命令的退出码以 cmd2 为准;
  • cmd1 && cmd2 仅当 cmd1 执行成功后,才会执行 cmd2,两条命令都执行成功,则整行命令的退出码为 0,有任意一个执行失败,整行命令的退出码为非 0;
  • cmd1 || cmd2 一般很少用,只有当 cmd1 不执行或者执行失败时才会执行 cmd2cmd1cmd2 是二选一的关系,两个中的任意一个执行成功,那么整条命令的退出码为 0,否则返回非 0;

10. 字符串比较

wohu@ubuntu:~$ test a == a
wohu@ubuntu:~$ echo $?
0
wohu@ubuntu:~$ test a == b; echo $?
1
wohu@ubuntu:~$ [ $USER == wohu ] && echo Y || echo N
Y
wohu@ubuntu:~$ [ $USER != wohu ] && echo Y || echo N
N
wohu@ubuntu:~$

表达式 -z 测试字符串是否为空。

wohu@ubuntu:~$ a=123
wohu@ubuntu:~$ [ -z $a ] && echo Y || echo N
N
wohu@ubuntu:~$ [ -z $b ] && echo Y || echo N
Y
wohu@ubuntu:~$

Shell 中进行条件测试时一定要注意空格问题,使用 [] 测试时,左括号右边和右括号左边都必须要有空格,而且测试的比较符号两边也必须都有空格。

wohu@ubuntu:~$ [a == city] # 前后都缺少空格,报错
[a: command not found
wohu@ubuntu:~$

下面的例子,== 符号两边都没有空格,无论怎么测试结果都为真,编写脚本时这种 Bug 系统不会提示语法错误,但是程序结果有可能是错误的。

wohu@ubuntu:~$ [ a==city ]; echo $?               # 退出码是错误的
0
wohu@ubuntu:~$ [ a == city ]; echo $?
1
wohu@ubuntu:~$

还可以使用 -n 测试一个字符串是否为非空,在实际应用时最好将测试对象使用双引号引起来。否则当测试一个未定义的变量时就会出现下面的问题。

wohu@ubuntu:~$ [ -n $str ]; echo $?
0
wohu@ubuntu:~$

因为当 $str 为空时,等同于执行了下面的第一条命令,是在测试一个空格是否为空值。而计算机理解空格也是有值的,并非没有值(空值),所以这样的测试结果总为真。

wohu@ubuntu:~$ [ -n ] && echo Y  || echo N
Y
wohu@ubuntu:~$

为了避免这样的错误,可以使用双引号将变量引起来。

wohu@ubuntu:~$ [ -n "$str" ]; echo $?
1
wohu@ubuntu:~$ [ -n "$str"] && echo Y  || echo N  # 右方括号前没有空格,导致结果错误,切记
Y
wohu@ubuntu:~$ [ -n "$str" ] && echo Y  || echo N
N
wohu@ubuntu:~$

Shell 脚本 — 多行注释、开启子/不开启子进程执行、转义带颜色输出、读取键盘输入、输入输出重定向、单双引号、命令替换、读取变量、系统变量、正则过滤、算术运算、一行多条命令、字符串比较相关推荐

  1. 【shell】实现交互|read读取键盘输入

    目录 一.SHELL 1.1 输入单个指令 1.2 输入多行指令 限制输入内容的个数 控制输入内容的可见性 二.Expect 简介 for 中嵌套 expect 在expect中使用shell的环境变 ...

  2. 编写shell脚步--读取键盘输入

    文章目录 一.read--从标准输入读取输入值 1.1.选项 1.2.使用IFS间隔输入字段 二.验证输入 三.菜单 一.read–从标准输入读取输入值 内嵌命令read的作用是读取一行标准输入.此命 ...

  3. Linux下sed命令替换配置文件中某个变量的值(改变包含字符的一行的值)之二——只改变第一出现的那一行

    一.背景 在之前的文章中有介绍过<Linux下sed命令替换配置文件中某个变量的值(改变包含字符的一行的值)> 但是这种方法存在一定的问题,就是假如某个变量在一个文件中出现两次,却只想更改 ...

  4. DM8联机逻辑备份perl脚本实现要点(单双引号、system和disql)

    概要 此文章非完整脚本功能分享,仅就实现逻辑备份功能进行分享. 问题背景 在编写DM8自动化备份perl脚本中,在涉及联机物理库级备份时,需要执行相关操作,正常情况下,相应语句如下(已简写,便于理解) ...

  5. python 输出引号_python输出字符串单双引号如何选择

    在Python当中字符串的输出既可以使用单引号,也可以使用双引号,使用单引号或双引号是没有区别的:当使用双引号将输出的字符串括起来时,内部也可使用单引号,将单双引号匹配正确即可. 在Python中我们 ...

  6. linux如何过滤字符串,在linux系统如何grep过滤中,不包含某些字符串的命令

    转:http://www.dutycode.com/linux_grep_bubaohan.html 文章系转载,亲测可用(转载自:http://www.itokit.com/2014/0105/75 ...

  7. python 并发执行命令_python: 多线程实现的两种方式及让多条命令并发执行

    一 概念介绍 Thread 是threading模块中最重要的类之一,可以使用它来创建线程.有两种方式来创建线程:一种是通过继承Thread类,重写它的run方法:另一种是创建一个threading. ...

  8. python中执行shell脚本之subprocess模块,python用subprocess执行shell脚本

    用subprocess中的Popen() 方法来得到shell脚本的一些运行结果,并且也可以指定不同的shell内核. 其构造函数为: class subprocess.Popen(args, buf ...

  9. linux shell 引号 参数,shell(三)变量,基本语法,单双引号

    shell中的变量 变量的声明:在shell中变量不需要事先声明,不必显示声明 变量的赋值:VAR=value,不允许有空格.如:a=100 变量的数据类型:shell中的变量无数据(弱)类型!同一变 ...

最新文章

  1. BigMemroy系列文章--11. BigMemory中的SizeOf问题
  2. 2.4带通采样的实际问题
  3. tp剩余未验证内容-7
  4. 23种设计模式C++源码与UML实现--访问者模式
  5. YbtOJ#20067-[NOIP2020模拟赛B组Day5]糖果分配【dp】
  6. 七月老师python_七月在线Python学习笔记
  7. 【codevs1565】【BZOJ2242】计算器,数论练习
  8. PDF文件分割电脑版怎么操作
  9. 【路径规划】基于matlab A_star算法机器人走迷宫路径规划【含Matlab源码 1389期】
  10. 半监督学习和直推式学习
  11. java中文转英文_eclipse英文转中文怎么设置 eclipse中英文切换图文教程
  12. EasyExcel3.0.5 解决大数据导入导出,防止OOM
  13. html弹窗后 自动关闭页面,网页一键复制弹出提示窗口后几秒后自动关闭提示js代码...
  14. sprint 1 总结
  15. 显卡测试软件毛毛虫,ATI Radeon Xpress200M与Intel GMA950谁强些?
  16. nginx: [warn] conflicting server name 这里是域名 eg:abc.com on 0.0.0.0:80, ignored解决方法
  17. 【JQuery】关于jQuery的load方法在Laravel里的使用
  18. 华为思科宣布全力布局,美国NSF巨资支持的NDN到底什么来头?
  19. 注册苹果开发者帐号 用什么银行的什么卡好? 收款帐号呢?
  20. 二、执行v8引擎示例代码

热门文章

  1. c++ 关于heap的STL用法
  2. el-table表格数据 中文 键值渲染
  3. php做网站需要注意什么,浅谈新手做网站应该注意的问题
  4. 2022起重机械指挥考试题库模拟考试平台操作
  5. Halcon 算子 elliptic_axis
  6. 超详细的Android so库的逆向调试
  7. BT下载伤硬盘的解决办法
  8. Java面向对象-01-类和对象
  9. linux常用c函数(中文版)
  10. EasyNVR流媒体直播之:零基础实现摄像头的全平台直播 (一)内网直播的实现