Linux笔记(三)——Shell编程
预备知识
1.Shell是解释执行的脚本语言,可以直接调用Linux系统命令
2.文件以.sh结尾, #!bin/bash 标识, 说明这是一个shell脚本, 不能省略
3.执行
- 赋予权限,直接运行
- bash
4.命令执行顺序
(1).绝对路径或相对路径执行的命令
(2).别名【临时:alias vi='vim', 删除unalias; 永久生效: vi /root/.bashrc】
(3).bash 内部命令
(4).按照$PATH找到的第一个命令
Linux重定向linux重定向
- 输入到屏幕的内容转为输入到文件中
- 内容由键盘输入改为从文件中输入
通配符 linux shell通配符
| 字符 | 含义 | 实例 | 
| * | 匹配 0 或多个字符 | a*b a与b之间可以有任意长度的任意字符, 也可以一个也没有, 如aabcb, axyzb, a012b, ab。 | 
| ? | 匹配任意一个字符 | a?b a与b之间必须也只能有一个字符, 可以是任意字符, 如aab, abb, acb, a0b。 | 
| [list] | 匹配 list 中的任意单一字符 | a[xyz]b a与b之间必须也只能有一个字符, 但只能是 x 或 y 或 z, 如: axb, ayb, azb。 | 
| [!list] | 匹配 除list 中的任意单一字符 | a[!0-9]b a与b之间必须也只能有一个字符, 但不能是阿拉伯数字, 如axb, aab, a-b。 | 
| [c1-c2] | 匹配 c1-c2 中的任意单一字符 如:[0-9] [a-z] | a[0-9]b 0与9之间必须也只能有一个字符 如a0b, a1b... a9b。 | 
| {string1,string2,...} | 匹配 sring1 或 string2 (或更多)其一字符串 | a{abc,xyz,123}b a与b之间只能是abc或xyz或123这三个字符串之一。 | 
添加环境变量
- 临时 PATH="$PATH":/home/hichens/sh
- 永久
1、修改profile文件:
修 改/etc/profile(对所有用户都是有效的)
在里面加入:
export PATH="$PATH:/home/xyz/Tesseract/bin"
2、 修改.bashrc文件:
修改~/.bashrc文件。  (每个用户目录下都有,ls -all,单独用户有效)
cd ~
vi .bashrc
在里面加入:
export PATH="$PATH:/opt/au1200_rm/build_tools/bin"
Shell语法
1. 简介
1.1. 什么是 shell
- Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。
- Shell 既是一种命令语言,又是一种程序设计语言。
- Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问 Linux 内核的服务。
Ken Thompson 的 sh 是第一种 Unix Shell,Windows Explorer 是一个典型的图形界面 Shell。
1.2. 什么是 shell 脚本
Shell 脚本(shell script),是一种为 shell 编写的脚本程序,一般文件后缀为 .sh。
业界所说的 shell 通常都是指 shell 脚本,但 shell 和 shell script 是两个不同的概念。
1.3. Shell 环境
Shell 编程跟 java、php 编程一样,只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就可以了。
Shell 的解释器种类众多,常见的有:
- sh - 即 Bourne Shell。sh 是 Unix 标准默认的 shell。
- bash - 即 Bourne Again Shell。bash 是 Linux 标准默认的 shell。
- fish - 智能和用户友好的命令行 shell。
- xiki - 使 shell 控制台更友好,更强大。
- zsh - 功能强大的 shell 与脚本语言。
指定脚本解释器
在 shell 脚本,#! 告诉系统其后路径所指定的程序即是解释此脚本文件的 Shell 解释器。#! 被称作shebang(也称为 Hashbang )。
所以,你应该会在 shell 中,见到诸如以下的注释:
- 指定 sh 解释器
#!/bin/sh- 指定 bash 解释器
#!/bin/bash注意
上面的指定解释器的方式是比较常见的,但有时候,你可能也会看到下面的方式:
#!/usr/bin/env bash这样做的好处是,系统会自动在
PATH环境变量中查找你指定的程序(本例中的bash)。相比第一种写法,你应该尽量用这种写法,因为程序的路径是不确定的。这样写还有一个好处,操作系统的PATH变量有可能被配置为指向程序的另一个版本。比如,安装完新版本的bash,我们可能将其路径添加到PATH中,来“隐藏”老版本。如果直接用#!/bin/bash,那么系统会选择老版本的bash来执行脚本,如果用#!/usr/bin/env bash,则会使用新版本。
1.4. 模式
shell 有交互和非交互两种模式。
交互模式
简单来说,你可以将 shell 的交互模式理解为执行命令行。
看到形如下面的东西,说明 shell 处于交互模式下:
user@host:~$接着,便可以输入一系列 Linux 命令,比如 ls,grep,cd,mkdir,rm 等等。
非交互模式
简单来说,你可以将 shell 的非交互模式理解为执行 shell 脚本。
在非交互模式下,shell 从文件或者管道中读取命令并执行。
当 shell 解释器执行完文件中的最后一个命令,shell 进程终止,并回到父进程。
可以使用下面的命令让 shell 以非交互模式运行:
sh /path/to/script.sh
bash /path/to/script.sh
source /path/to/script.sh
./path/to/script.sh上面的例子中,script.sh是一个包含 shell 解释器可以识别并执行的命令的普通文本文件,sh和bash是 shell 解释器程序。你可以使用任何喜欢的编辑器创建script.sh(vim,nano,Sublime Text, Atom 等等)。
其中,source /path/to/script.sh 和 ./path/to/script.sh 是等价的。
除此之外,你还可以通过chmod命令给文件添加可执行的权限,来直接执行脚本文件:
chmod +x /path/to/script.sh #使脚本具有执行权限
/path/to/test.sh这种方式要求脚本文件的第一行必须指明运行该脚本的程序,比如:
:keyboard: 『示例源码』 helloworld.sh
#!/usr/bin/env bash
echo "Hello, world!"上面的例子中,我们使用了一个很有用的命令echo来输出字符串到屏幕上。
2. 基本语法
2.1. 解释器
前面虽然两次提到了#! ,但是本着重要的事情说三遍的精神,这里再强调一遍:
在 shell 脚本,#! 告诉系统其后路径所指定的程序即是解释此脚本文件的 Shell 解释器。#! 被称作shebang(也称为 Hashbang )。
#! 决定了脚本可以像一个独立的可执行文件一样执行,而不用在终端之前输入sh, bash, python, php等。
# 以下两种方式都可以指定 shell 解释器为 bash,第二种方式更好
#!/bin/bash
#!/usr/bin/env bash2.2. 注释
注释可以说明你的代码是什么作用,以及为什么这样写。
shell 语法中,注释是特殊的语句,会被 shell 解释器忽略。
- 单行注释 - 以 #开头,到行尾结束。
- 多行注释 - 以 :<<EOF开头,到EOF结束。
:keyboard: 『示例源码』 comment-demo.sh
#--------------------------------------------
# shell 注释示例
# author:zp
#--------------------------------------------
# echo '这是单行注释'
########## 这是分割线 ##########
:<<EOF
echo '这是多行注释'
echo '这是多行注释'
echo '这是多行注释'
EOF2.3. echo
echo 用于字符串的输出。
输出普通字符串:
echo "hello, world"
# Output: hello, world输出含变量的字符串:
echo "hello, \"zp\""
# Output: hello, "zp"输出含变量的字符串:
name=zp
echo "hello, \"${name}\""
# Output: hello, "zp"输出含换行符的字符串:
# 输出含换行符的字符串
echo "YES\nNO"
#  Output: YES\nNO
echo -e "YES\nNO" # -e 开启转义
#  Output:
#  YES
#  NO输出含不换行符的字符串:
echo "YES"
echo "NO"
#  Output:
#  YES
#  NO
echo -e "YES\c" # -e 开启转义 \c 不换行
echo "NO"
#  Output:
#  YESNO输出重定向至文件
echo "test" > test.txt输出执行结果
echo `pwd`
#  Output:(当前目录路径):keyboard: 『示例源码』 echo-demo.sh
2.4. printf
printf 用于格式化输出字符串。
默认,printf 不会像 echo 一样自动添加换行符,如果需要换行可以手动添加 \n。
:keyboard: 『示例源码』 printf-demo.sh
# 单引号
printf '%d %s\n' 1 "abc"
#  Output:1 abc
# 双引号
printf "%d %s\n" 1 "abc"
#  Output:1 abc
# 无引号
printf %s abcdef
#  Output: abcdef(并不会换行)
# 格式只指定了一个参数,但多出的参数仍然会按照该格式输出
printf "%s\n" abc def
#  Output:
#  abc
#  def
printf "%s %s %s\n" a b c d e f g h i j
#  Output:
#  a b c
#  d e f
#  g h i
#  j
# 如果没有参数,那么 %s 用 NULL 代替,%d 用 0 代替
printf "%s and %d \n"
#  Output:
#   and 0
# 格式化输出
printf "%-10s %-8s %-4s\n" 姓名 性别 体重kg
printf "%-10s %-8s %-4.2f\n" 郭靖 男 66.1234
printf "%-10s %-8s %-4.2f\n" 杨过 男 48.6543
printf "%-10s %-8s %-4.2f\n" 郭芙 女 47.9876
#  Output:
#  姓名     性别   体重kg
#  郭靖     男      66.12
#  杨过     男      48.65
#  郭芙     女      47.99printf 的转义符
| 序列 | 说明 | 
|---|---|
| \a | 警告字符,通常为 ASCII 的 BEL 字符 | 
| \b | 后退 | 
| \c | 抑制(不显示)输出结果中任何结尾的换行字符(只在%b 格式指示符控制下的参数字符串中有效),而且,任何留在参数里的字符、任何接下来的参数以及任何留在格式字符串中的字符,都被忽略 | 
| \f | 换页(formfeed) | 
| \n | 换行 | 
| \r | 回车(Carriage return) | 
| \t | 水平制表符 | 
| \v | 垂直制表符 | 
| \\ | 一个字面上的反斜杠字符 | 
| \ddd | 表示 1 到 3 位数八进制值的字符。仅在格式字符串中有效 | 
| \0ddd | 表示 1 到 3 位的八进制值字符 | 
3. 变量
跟许多程序设计语言一样,你可以在 bash 中创建变量。
Bash 中没有数据类型,bash 中的变量可以保存一个数字、一个字符、一个字符串等等。同时无需提前声明变量,给变量赋值会直接创建变量。
3.1. 变量命名原则
- 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头。
- 中间不能有空格,可以使用下划线(_)。
- 不能使用标点符号。
- 不能使用 bash 里的关键字(可用 help 命令查看保留关键字)。
3.2. 声明变量
访问变量的语法形式为:${var} 和 $var 。
变量名外面的花括号是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界,所以推荐加花括号。
word="hello"
echo ${word}
# Output: hello3.3. 只读变量
使用 readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变。
rword="hello"
echo ${rword}
readonly rword
# rword="bye"  # 如果放开注释,执行时会报错3.4. 删除变量
使用 unset 命令可以删除变量。变量被删除后不能再次使用。unset 命令不能删除只读变量。
dword="hello"  # 声明变量
echo ${dword}  # 输出变量值
# Output: hello
unset dword    # 删除变量
echo ${dword}
# Output: (空)3.5. 变量类型
- 局部变量 - 局部变量是仅在某个脚本内部有效的变量。它们不能被其他的程序和脚本访问。
- 环境变量 - 环境变量是对当前 shell 会话内所有的程序或脚本都可见的变量。创建它们跟创建局部变量类似,但使用的是 export关键字,shell 脚本也可以定义环境变量。
常见的环境变量:
| 变量 | 描述 | 
|---|---|
| $HOME | 当前用户的用户目录 | 
| $PATH | 用分号分隔的目录列表,shell 会到这些目录中查找命令 | 
| $PWD | 当前工作目录 | 
| $RANDOM | 0 到 32767 之间的整数 | 
| $UID | 数值类型,当前用户的用户 ID | 
| $PS1 | 主要系统输入提示符 | 
| $PS2 | 次要系统输入提示符 | 
这里 有一张更全面的 Bash 环境变量列表。
3.6. 变量示例源码
⌨️ 『示例源码』 variable-demo.sh
4. 字符串
4.1. 单引号和双引号
shell 字符串可以用单引号 '',也可以用双引号 “”,也可以不用引号。
- 单引号的特点
- 单引号里不识别变量
- 单引号里不能出现单独的单引号(使用转义符也不行),但可成对出现,作为字符串拼接使用。
 
- 双引号的特点
- 双引号里识别变量
- 双引号里可以出现转义字符
 
综上,推荐使用双引号。
4.2. 拼接字符串
# 使用单引号拼接
name1='white'
str1='hello, '${name1}''
str2='hello, ${name1}'
echo ${str1}_${str2}
# Output:
# hello, white_hello, ${name1}
# 使用双引号拼接
name2="black"
str3="hello, "\({name2}</span><span class="hljs-string">""</span>
str4=<span class="hljs-string">"hello, <span class="hljs-variable">\){name2}"
echo \({str3}</span>_<span class="hljs-variable">\){str4}
# Output:
# hello, black_hello, black4.3. 获取字符串长度
text="12345"
echo ${#text}
# Output:
# 54.4. 截取子字符串
text="12345"
echo ${text:2:2}
# Output:
# 34从第 3 个字符开始,截取 2 个字符
4.5. 查找子字符串
#!/usr/bin/env bash
text="hello"
echo `expr index "${text}" ll`
# Execute: ./str-demo5.sh
# Output:
# 3查找 ll 子字符在 hello 字符串中的起始位置。
4.6. 字符串示例源码
⌨️ 『示例源码』 string-demo.sh
5. 数组
bash 只支持一维数组。
数组下标从 0 开始,下标可以是整数或算术表达式,其值应大于或等于 0。
5.1. 创建数组
# 创建数组的不同方式
nums=([2]=2 [0]=0 [1]=1)
colors=(red yellow "dark blue")5.2. 访问数组元素
- 访问数组的单个元素:
echo ${nums[1]}
# Output: 1- 访问数组的所有元素:
echo ${colors[*]}
# Output: red yellow dark blue
echo ${colors[@]}
# Output: red yellow dark blue上面两行有很重要(也很微妙)的区别:
为了将数组中每个元素单独一行输出,我们用 printf 命令:
printf "+ %s\n" ${colors[*]}
# Output:
# + red
# + yellow
# + dark
# + blue为什么dark和blue各占了一行?尝试用引号包起来:
printf "+ %s\n" "${colors[*]}"
# Output:
# + red yellow dark blue现在所有的元素都在一行输出 —— 这不是我们想要的!让我们试试${colors[@]}
printf "+ %s\n" "${colors[@]}"
# Output:
# + red
# + yellow
# + dark blue在引号内,${colors[@]}将数组中的每个元素扩展为一个单独的参数;数组元素中的空格得以保留。
- 访问数组的部分元素:
echo ${nums[@]:0:2}
# Output:
# 0 1在上面的例子中,${array[@]} 扩展为整个数组,:0:2取出了数组中从 0 开始,长度为 2 的元素。
5.3. 访问数组长度
echo ${#nums[*]}
# Output:
# 35.4. 向数组中添加元素
向数组中添加元素也非常简单:
colors=(white "${colors[@]}" green black)
echo ${colors[@]}
# Output:
# white red yellow dark blue green black上面的例子中,${colors[@]} 扩展为整个数组,并被置换到复合赋值语句中,接着,对数组colors的赋值覆盖了它原来的值。
5.5. 从数组中删除元素
用unset命令来从数组中删除一个元素:
unset nums[0]
echo ${nums[@]}
# Output:
# 1 25.6. 数组示例源码
:keyboard: 『示例源码』 array-demo.sh
6. 运算符
6.1. 算术运算符
下表列出了常用的算术运算符,假定变量 x 为 10,变量 y 为 20:
| 运算符 | 说明 | 举例 | 
|---|---|---|
| + | 加法 | expr $x + $y结果为 30。 | 
| - | 减法 | expr $x - $y结果为 -10。 | 
| * | 乘法 | expr $x * $y结果为 200。 | 
| / | 除法 | expr $y / $x结果为 2。 | 
| % | 取余 | expr $y % $x结果为 0。 | 
| = | 赋值 | x=$y将把变量 y 的值赋给 x。 | 
| == | 相等。用于比较两个数字,相同则返回 true。 | [ $x == $y ]返回 false。 | 
| != | 不相等。用于比较两个数字,不相同则返回 true。 | [ $x != $y ]返回 true。 | 
注意:条件表达式要放在方括号之间,并且要有空格,例如: [$x==$y] 是错误的,必须写成 [ $x == $y ]。
:keyboard: 『示例源码』 operator-demo.sh
x=10
y=20
echo "x=\({x}</span>, y=<span class="hljs-variable">\){y}"
val=expr <span class="hljs-variable">${x}</span> + <span class="hljs-variable">${y}</span>
echo "\({x}</span> + <span class="hljs-variable">\){y} = $val"
val=expr <span class="hljs-variable">${x}</span> - <span class="hljs-variable">${y}</span>
echo "\({x}</span> - <span class="hljs-variable">\){y} = $val"
val=expr <span class="hljs-variable">${x}</span> \* <span class="hljs-variable">${y}</span>
echo "\({x}</span> * <span class="hljs-variable">\){y} = $val"
val=expr <span class="hljs-variable">${y}</span> / <span class="hljs-variable">${x}</span>
echo "\({y}</span> / <span class="hljs-variable">\){x} = $val"
val=expr <span class="hljs-variable">${y}</span> % <span class="hljs-variable">${x}</span>
echo "\({y}</span> % <span class="hljs-variable">\){x} = $val"
if [[ \({x}</span> == <span class="hljs-variable">\){y} ]]
then
echo "\({x}</span> = <span class="hljs-variable">\){y}"
fi
if [[ \({x}</span> != <span class="hljs-variable">\){y} ]]
then
echo "\({x}</span> != <span class="hljs-variable">\){y}"
fi
#  Execute: ./operator-demo.sh
#  Output:
#  x=10, y=20
#  10 + 20 = 30
#  10 - 20 = -10
#  10 * 20 = 200
#  20 / 10 = 2
#  20 % 10 = 0
#  10 != 206.2. 关系运算符
关系运算符只支持数字,不支持字符串,除非字符串的值是数字。
下表列出了常用的关系运算符,假定变量 x 为 10,变量 y 为 20:
| 运算符 | 说明 | 举例 | 
|---|---|---|
| -eq | 检测两个数是否相等,相等返回 true。 | [ $a -eq $b ]返回 false。 | 
| -ne | 检测两个数是否相等,不相等返回 true。 | [ $a -ne $b ]返回 true。 | 
| -gt | 检测左边的数是否大于右边的,如果是,则返回 true。 | [ $a -gt $b ]返回 false。 | 
| -lt | 检测左边的数是否小于右边的,如果是,则返回 true。 | [ $a -lt $b ]返回 true。 | 
| -ge | 检测左边的数是否大于等于右边的,如果是,则返回 true。 | [ $a -ge $b ]返回 false。 | 
| -le | 检测左边的数是否小于等于右边的,如果是,则返回 true。 | [ $a -le $b ]返回 true。 | 
:keyboard: 『示例源码』 operator-demo2.sh
x=10
y=20
echo "x=\({x}</span>, y=<span class="hljs-variable">\){y}"
if [[ \({x}</span> -eq <span class="hljs-variable">\){y} ]]; then
echo "\({x}</span> -eq <span class="hljs-variable">\){y} : x 等于 y"
else
echo "\({x}</span> -eq <span class="hljs-variable">\){y}: x 不等于 y"
fi
if [[ \({x}</span> -ne <span class="hljs-variable">\){y} ]]; then
echo "\({x}</span> -ne <span class="hljs-variable">\){y}: x 不等于 y"
else
echo "\({x}</span> -ne <span class="hljs-variable">\){y}: x 等于 y"
fi
if [[ \({x}</span> -gt <span class="hljs-variable">\){y} ]]; then
echo "\({x}</span> -gt <span class="hljs-variable">\){y}: x 大于 y"
else
echo "\({x}</span> -gt <span class="hljs-variable">\){y}: x 不大于 y"
fi
if [[ \({x}</span> -lt <span class="hljs-variable">\){y} ]]; then
echo "\({x}</span> -lt <span class="hljs-variable">\){y}: x 小于 y"
else
echo "\({x}</span> -lt <span class="hljs-variable">\){y}: x 不小于 y"
fi
if [[ \({x}</span> -ge <span class="hljs-variable">\){y} ]]; then
echo "\({x}</span> -ge <span class="hljs-variable">\){y}: x 大于或等于 y"
else
echo "\({x}</span> -ge <span class="hljs-variable">\){y}: x 小于 y"
fi
if [[ \({x}</span> -le <span class="hljs-variable">\){y} ]]; then
echo "\({x}</span> -le <span class="hljs-variable">\){y}: x 小于或等于 y"
else
echo "\({x}</span> -le <span class="hljs-variable">\){y}: x 大于 y"
fi
#  Execute: ./operator-demo2.sh
#  Output:
#  x=10, y=20
#  10 -eq 20: x 不等于 y
#  10 -ne 20: x 不等于 y
#  10 -gt 20: x 不大于 y
#  10 -lt 20: x 小于 y
#  10 -ge 20: x 小于 y
#  10 -le 20: x 小于或等于 y6.3. 布尔运算符
下表列出了常用的布尔运算符,假定变量 x 为 10,变量 y 为 20:
| 运算符 | 说明 | 举例 | 
|---|---|---|
| ! | 非运算,表达式为 true 则返回 false,否则返回 true。 | [ ! false ]返回 true。 | 
| -o | 或运算,有一个表达式为 true 则返回 true。 | [ $a -lt 20 -o $b -gt 100 ]返回 true。 | 
| -a | 与运算,两个表达式都为 true 才返回 true。 | [ $a -lt 20 -a $b -gt 100 ]返回 false。 | 
:keyboard: 『示例源码』 operator-demo3.sh
x=10
y=20
echo "x=\({x}</span>, y=<span class="hljs-variable">\){y}"
if [[ \({x}</span> != <span class="hljs-variable">\){y} ]]; then
echo "\({x}</span> != <span class="hljs-variable">\){y} : x 不等于 y"
else
echo "\({x}</span> != <span class="hljs-variable">\){y}: x 等于 y"
fi
if [[ \({x}</span> -lt 100 && <span class="hljs-variable">\){y} -gt 15 ]]; then
echo "\({x}</span> 小于 100 且 <span class="hljs-variable">\){y} 大于 15 : 返回 true"
else
echo "\({x}</span> 小于 100 且 <span class="hljs-variable">\){y} 大于 15 : 返回 false"
fi
if [[ \({x}</span> -lt 100 || <span class="hljs-variable">\){y} -gt 100 ]]; then
echo "\({x}</span> 小于 100 或 <span class="hljs-variable">\){y} 大于 100 : 返回 true"
else
echo "\({x}</span> 小于 100 或 <span class="hljs-variable">\){y} 大于 100 : 返回 false"
fi
if [[ \({x}</span> -lt 5 || <span class="hljs-variable">\){y} -gt 100 ]]; then
echo "\({x}</span> 小于 5 或 <span class="hljs-variable">\){y} 大于 100 : 返回 true"
else
echo "\({x}</span> 小于 5 或 <span class="hljs-variable">\){y} 大于 100 : 返回 false"
fi
#  Execute: ./operator-demo3.sh
#  Output:
#  x=10, y=20
#  10 != 20 : x 不等于 y
#  10 小于 100 且 20 大于 15 : 返回 true
#  10 小于 100 或 20 大于 100 : 返回 true
#  10 小于 5 或 20 大于 100 : 返回 false6.4. 逻辑运算符
以下介绍 Shell 的逻辑运算符,假定变量 x 为 10,变量 y 为 20:
| 运算符 | 说明 | 举例 | 
|---|---|---|
| && | 逻辑的 AND | [[ ${x} -lt 100 && ${y} -gt 100 ]]返回 false | 
| || | 逻辑的 OR | [[ ${x} -lt 100 || ${y} -gt 100 ]]返回 true | 
:keyboard: 『示例源码』 operator-demo4.sh
x=10
y=20
echo "x=\({x}</span>, y=<span class="hljs-variable">\){y}"
if [[ \({x}</span> -lt 100 && <span class="hljs-variable">\){y} -gt 100 ]]
then
echo "\({x}</span> -lt 100 && <span class="hljs-variable">\){y} -gt 100 返回 true"
else
echo "\({x}</span> -lt 100 && <span class="hljs-variable">\){y} -gt 100 返回 false"
fi
if [[ \({x}</span> -lt 100 || <span class="hljs-variable">\){y} -gt 100 ]]
then
echo "\({x}</span> -lt 100 || <span class="hljs-variable">\){y} -gt 100 返回 true"
else
echo "\({x}</span> -lt 100 || <span class="hljs-variable">\){y} -gt 100 返回 false"
fi
#  Execute: ./operator-demo4.sh
#  Output:
#  x=10, y=20
#  10 -lt 100 && 20 -gt 100 返回 false
#  10 -lt 100 || 20 -gt 100 返回 true6.5. 字符串运算符
下表列出了常用的字符串运算符,假定变量 a 为 "abc",变量 b 为 "efg":
| 运算符 | 说明 | 举例 | 
|---|---|---|
| = | 检测两个字符串是否相等,相等返回 true。 | [ $a = $b ]返回 false。 | 
| != | 检测两个字符串是否相等,不相等返回 true。 | [ $a != $b ]返回 true。 | 
| -z | 检测字符串长度是否为 0,为 0 返回 true。 | [ -z $a ]返回 false。 | 
| -n | 检测字符串长度是否为 0,不为 0 返回 true。 | [ -n $a ]返回 true。 | 
| str | 检测字符串是否为空,不为空返回 true。 | [ $a ]返回 true。 | 
:keyboard: 『示例源码』 operator-demo5.sh
x="abc"
y="xyz"
echo "x=\({x}</span>, y=<span class="hljs-variable">\){y}"
if [[ \({x}</span> = <span class="hljs-variable">\){y} ]]; then
echo "\({x}</span> = <span class="hljs-variable">\){y} : x 等于 y"
else
echo "\({x}</span> = <span class="hljs-variable">\){y}: x 不等于 y"
fi
if [[ \({x}</span> != <span class="hljs-variable">\){y} ]]; then
echo "\({x}</span> != <span class="hljs-variable">\){y} : x 不等于 y"
else
echo "\({x}</span> != <span class="hljs-variable">\){y}: x 等于 y"
fi
if [[ -z \({x}</span> ]]; <span class="hljs-keyword">then</span>
   <span class="hljs-built_in">echo</span> <span class="hljs-string">"-z <span class="hljs-variable">\){x} : 字符串长度为 0"
else
echo "-z ${x} : 字符串长度不为 0"
fi
if [[ -n "\({x}</span>"</span> ]]; <span class="hljs-keyword">then</span>
   <span class="hljs-built_in">echo</span> <span class="hljs-string">"-n <span class="hljs-variable">\){x} : 字符串长度不为 0"
else
echo "-n ${x} : 字符串长度为 0"
fi
if [[ \({x}</span> ]]; <span class="hljs-keyword">then</span>
   <span class="hljs-built_in">echo</span> <span class="hljs-string">"<span class="hljs-variable">\){x} : 字符串不为空"
else
echo "${x} : 字符串为空"
fi
#  Execute: ./operator-demo5.sh
#  Output:
#  x=abc, y=xyz
#  abc = xyz: x 不等于 y
#  abc != xyz : x 不等于 y
#  -z abc : 字符串长度不为 0
#  -n abc : 字符串长度不为 0
#  abc : 字符串不为空6.6. 文件测试运算符
文件测试运算符用于检测 Unix 文件的各种属性。
属性检测描述如下:
| 操作符 | 说明 | 举例 | 
|---|---|---|
| -b file | 检测文件是否是块设备文件,如果是,则返回 true。 | [ -b $file ]返回 false。 | 
| -c file | 检测文件是否是字符设备文件,如果是,则返回 true。 | [ -c $file ]返回 false。 | 
| -d file | 检测文件是否是目录,如果是,则返回 true。 | [ -d $file ]返回 false。 | 
| -f file | 检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。 | [ -f $file ]返回 true。 | 
| -g file | 检测文件是否设置了 SGID 位,如果是,则返回 true。 | [ -g $file ]返回 false。 | 
| -k file | 检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true。 | [ -k $file ]返回 false。 | 
| -p file | 检测文件是否是有名管道,如果是,则返回 true。 | [ -p $file ]返回 false。 | 
| -u file | 检测文件是否设置了 SUID 位,如果是,则返回 true。 | [ -u $file ]返回 false。 | 
| -r file | 检测文件是否可读,如果是,则返回 true。 | [ -r $file ]返回 true。 | 
| -w file | 检测文件是否可写,如果是,则返回 true。 | [ -w $file ]返回 true。 | 
| -x file | 检测文件是否可执行,如果是,则返回 true。 | [ -x $file ]返回 true。 | 
| -s file | 检测文件是否为空(文件大小是否大于 0),不为空返回 true。 | [ -s $file ]返回 true。 | 
| -e file | 检测文件(包括目录)是否存在,如果是,则返回 true。 | [ -e $file ]返回 true。 | 
:keyboard: 『示例源码』 operator-demo6.sh
file="/etc/hosts"
if [[ -r \({file}</span> ]]; <span class="hljs-keyword">then</span>
   <span class="hljs-built_in">echo</span> <span class="hljs-string">"<span class="hljs-variable">\){file} 文件可读"
else
echo "\({file}</span> 文件不可读"</span>
<span class="hljs-keyword">fi</span>
<span class="hljs-keyword">if</span> [[ -w <span class="hljs-variable">\){file} ]]; then
echo "\({file}</span> 文件可写"</span>
<span class="hljs-keyword">else</span>
   <span class="hljs-built_in">echo</span> <span class="hljs-string">"<span class="hljs-variable">\){file} 文件不可写"
fi
if [[ -x \({file}</span> ]]; <span class="hljs-keyword">then</span>
   <span class="hljs-built_in">echo</span> <span class="hljs-string">"<span class="hljs-variable">\){file} 文件可执行"
else
echo "\({file}</span> 文件不可执行"</span>
<span class="hljs-keyword">fi</span>
<span class="hljs-keyword">if</span> [[ -f <span class="hljs-variable">\){file} ]]; then
echo "\({file}</span> 文件为普通文件"</span>
<span class="hljs-keyword">else</span>
   <span class="hljs-built_in">echo</span> <span class="hljs-string">"<span class="hljs-variable">\){file} 文件为特殊文件"
fi
if [[ -d \({file}</span> ]]; <span class="hljs-keyword">then</span>
   <span class="hljs-built_in">echo</span> <span class="hljs-string">"<span class="hljs-variable">\){file} 文件是个目录"
else
echo "\({file}</span> 文件不是个目录"</span>
<span class="hljs-keyword">fi</span>
<span class="hljs-keyword">if</span> [[ -s <span class="hljs-variable">\){file} ]]; then
echo "\({file}</span> 文件不为空"</span>
<span class="hljs-keyword">else</span>
   <span class="hljs-built_in">echo</span> <span class="hljs-string">"<span class="hljs-variable">\){file} 文件为空"
fi
if [[ -e \({file}</span> ]]; <span class="hljs-keyword">then</span>
   <span class="hljs-built_in">echo</span> <span class="hljs-string">"<span class="hljs-variable">\){file} 文件存在"
else
echo "${file} 文件不存在"
fi
#  Execute: ./operator-demo6.sh
#  Output:(根据文件的实际情况,输出结果可能不同)
#  /etc/hosts 文件可读
#  /etc/hosts 文件可写
#  /etc/hosts 文件不可执行
#  /etc/hosts 文件为普通文件
#  /etc/hosts 文件不是个目录
#  /etc/hosts 文件不为空
#  /etc/hosts 文件存在7. 控制语句
7.1. 条件语句
跟其它程序设计语言一样,Bash 中的条件语句让我们可以决定一个操作是否被执行。结果取决于一个包在[[ ]]里的表达式。
由[[ ]](sh中是[ ])包起来的表达式被称作 检测命令 或 基元。这些表达式帮助我们检测一个条件的结果。这里可以找到有关bash 中单双中括号区别的答案。
共有两个不同的条件表达式:if和case。
if
(1)if 语句
if在使用上跟其它语言相同。如果中括号里的表达式为真,那么then和fi之间的代码会被执行。fi标志着条件代码块的结束。
# 写成一行
if [[ 1 -eq 1 ]]; then echo "1 -eq 1 result is: true"; fi
# Output: 1 -eq 1 result is: true
# 写成多行
if [[ "abc" -eq "abc" ]]
then
echo ""abc" -eq "abc" result is: true"
fi
# Output: abc -eq abc result is: true(2)if else 语句
同样,我们可以使用if..else语句,例如:
if [[ 2 -ne 1 ]]; then
  echo "true"
else
  echo "false"
fi
# Output: true(3)if elif else 语句
有些时候,if..else不能满足我们的要求。别忘了if..elif..else,使用起来也很方便。
x=10
y=20
if [[ ${x} > ${y} ]]; then
   echo "${x} > ${y}"
elif [[ ${x} < ${y} ]]; then
   echo "${x} < ${y}"
else
   echo "${x} = ${y}"
fi
# Output: 10 < 20:keyboard: 『示例源码』 if-demo.sh
case
如果你需要面对很多情况,分别要采取不同的措施,那么使用case会比嵌套的if更有用。使用case来解决复杂的条件判断,看起来像下面这样:
:keyboard: 『示例源码』 case-demo.sh
exec
case ${oper} in
  "+")
    val=`expr ${x} + ${y}`
    echo "${x} + ${y} = ${val}"
  ;;
  "-")
    val=`expr ${x} - ${y}`
    echo "${x} - ${y} = ${val}"
  ;;
  "*")
    val=`expr ${x} \* ${y}`
    echo "${x} * ${y} = ${val}"
  ;;
  "/")
    val=`expr ${x} / ${y}`
    echo "${x} / ${y} = ${val}"
  ;;
  *)
    echo "Unknown oper!"
  ;;
esac每种情况都是匹配了某个模式的表达式。|用来分割多个模式,)用来结束一个模式序列。第一个匹配上的模式对应的命令将会被执行。*代表任何不匹配以上给定模式的模式。命令块儿之间要用;;分隔。
7.2. 循环语句
循环其实不足为奇。跟其它程序设计语言一样,bash 中的循环也是只要控制条件为真就一直迭代执行的代码块。
Bash 中有四种循环:for,while,until和select。
for循环
for与它在 C 语言中的姊妹非常像。看起来是这样:
for arg in elem1 elem2 ... elemN
do
  ### 语句
done在每次循环的过程中,arg依次被赋值为从elem1到elemN。这些值还可以是通配符或者大括号扩展。
当然,我们还可以把for循环写在一行,但这要求do之前要有一个分号,就像下面这样:
for i in {1..5}; do echo $i; done还有,如果你觉得for..in..do对你来说有点奇怪,那么你也可以像 C 语言那样使用for,比如:
for (( i = 0; i < 10; i++ )); do
  echo $i
done当我们想对一个目录下的所有文件做同样的操作时,for就很方便了。举个例子,如果我们想把所有的.bash文件移动到script文件夹中,并给它们可执行权限,我们的脚本可以这样写:
DIR=/home/zp
for FILE in ${DIR}/*.sh; do
  mv "$FILE" "${DIR}/scripts"
done
# 将 /home/zp 目录下所有 sh 文件拷贝到 /home/zp/scripts:keyboard: 『示例源码』 for-demo.sh
while循环
while循环检测一个条件,只要这个条件为 真,就执行一段命令。被检测的条件跟if..then中使用的基元并无二异。因此一个while循环看起来会是这样:
while [[ condition ]]
do
  ### 语句
done跟for循环一样,如果我们把do和被检测的条件写到一行,那么必须要在do之前加一个分号。
比如下面这个例子:
### 0到9之间每个数的平方
x=0
while [[ ${x} -lt 10 ]]; do
  echo $((x * x))
  x=$((x + 1))
done
#  Output:
#  0
#  1
#  4
#  9
#  16
#  25
#  36
#  49
#  64
#  81:keyboard: 『示例源码』 while-demo.sh
until循环
until循环跟while循环正好相反。它跟while一样也需要检测一个测试条件,但不同的是,只要该条件为 假 就一直执行循环:
x=0
until [[ ${x} -ge 5 ]]; do
  echo ${x}
  x=`expr ${x} + 1`
done
#  Output:
#  0
#  1
#  2
#  3
#  4:keyboard: 『示例源码』 until-demo.sh
select循环
select循环帮助我们组织一个用户菜单。它的语法几乎跟for循环一致:
select answer in elem1 elem2 ... elemN
do
  ### 语句
doneselect会打印elem1..elemN以及它们的序列号到屏幕上,之后会提示用户输入。通常看到的是$?(PS3变量)。用户的选择结果会被保存到answer中。如果answer是一个在1..N之间的数字,那么语句会被执行,紧接着会进行下一次迭代 —— 如果不想这样的话我们可以使用break语句。
一个可能的实例可能会是这样:
#!/usr/bin/env bash
PS3="Choose the package manager: "
select ITEM in bower npm gem pip
do
echo -n "Enter the package name: " && read PACKAGE
case ${ITEM} in
  bower) bower install ${PACKAGE} ;;
  npm) npm install ${PACKAGE} ;;
  gem) gem install ${PACKAGE} ;;
  pip) pip install ${PACKAGE} ;;
esac
break # 避免无限循环
done这个例子,先询问用户他想使用什么包管理器。接着,又询问了想安装什么包,最后执行安装操作。
运行这个脚本,会得到如下输出:
$ ./my_script
1) bower
2) npm
3) gem
4) pip
Choose the package manager: 2
Enter the package name: gitbook-cli:keyboard: 『示例源码』 select-demo.sh
break 和 continue
如果想提前结束一个循环或跳过某次循环执行,可以使用 shell 的break和continue语句来实现。它们可以在任何循环中使用。
break语句用来提前结束当前循环。
continue语句用来跳过某次迭代。
:keyboard: 『示例源码』 break-demo.sh
# 查找 10 以内第一个能整除 2 和 3 的正整数
i=1
while [[ ${i} -lt 10 ]]; do
  if [[ $((i % 3)) -eq 0 ]] && [[ $((i % 2)) -eq 0 ]]; then
    echo ${i}
    break;
  fi
  i=`expr ${i} + 1`
done
# Output: 6:keyboard: 『示例源码』 continue-demo.sh
# 打印10以内的奇数
for (( i = 0; i < 10; i ++ )); do
  if [[ $((i % 2)) -eq 0 ]]; then
    continue;
  fi
  echo ${i}
done
#  Output:
#  1
#  3
#  5
#  7
#  98. 函数
bash 函数定义语法如下:
[ function ] funname [()] {
    action;
    [return int;]
}
Linux笔记(三)——Shell编程的更多相关文章
- Linux笔记 #08# shell编程从零开始到低配学生管理系统
先熟悉一下基本语法(运行环境是装git的时候一起装的那个windows下的bash): #!/bin/bash # 实现两个函数 # appendToFile()追加一行到文件 # readFile( ...
- linux笔记:shell编程-文本处理命令
cut(字段提取命令,也叫列提取命令): printf(格式化输出命令): awk(awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理): sed(sed是一个很好 ...
- linux笔记:shell编程-正则表达式
正则表达式与通配符(正则表达式匹配字符串,是包含匹配:通配符匹配文件名,是完全匹配.): 基础正则表达式: 正则表达式示例:
- Linux学习笔记(17) Shell编程之基础
1. 正则表达式 (1) 正则表达式用来在文件中匹配符合条件的字符串,正则是包含匹配.grep.awk.sed等命令可以支持正则表达式:通配符用来匹配符合条件的文件名,通配符是完全匹配.ls.find ...
- Linux 与 unix shell编程指南——学习笔记
第一章 文件安全与权限 文件访问方式:读,写,执行. 针对用户:文件属主,同组用户,其它用户. 文件权限位最前面的字符代表文件类型,常用的如 d 目录:l 符号链 ...
- Linux下的Shell编程
从程序员的角度来看, Shell本身是一种用C语言编写的程序,从用户的角度来看,Shell是用户与Linux操作系统沟通的桥梁.用户既可以输入命令执行,又可以利用 Shell脚本编程,完成更加复杂的操 ...
- Linux学习之Shell编程基础
转自:http://my.oschina.net/itblog/blog/204410 1 语法基本介绍1.1 开头 程序必须以下面的行开始(必须方在文件的第一行): #!/bin/sh 符号#!用来 ...
- [No000014A]Linux简介与shell编程
Linux 介绍 内核 库: .so 共享对象,windows:dll 动态链接库 应用程序 Linux的基本原则: 1.由目的单一的小程序组成:组合小程序完成复杂任务: 2.一切皆文件: 3.尽量避 ...
- linux操作系统5 shell编程
知识内容: 1.shell编程预备知识 2.shell变量 3.表达式与运算符 4.分支循环语句 5.函数 一.shell编程预备知识 1.什么是shell编程 shell是与linux交互的基本工具 ...
- Linux下的shell编程入门
通常情况下,我们从命令行输入命令每输入一次就能够得到系统的一次响应.一旦需要我们一个接着一个的输入命令而最后才得到结果的时候,这样的做法显然就没有效率.要达到这样的目的,通常我们利用shell程序或者 ...
随机推荐
- [NCTF2019]Fake XML cookbook
0x00 知识点 XXE攻击 附上链接: https://xz.aliyun.com/t/6887 XXE(XML External Entity Injection)全称为XML外部实体注入 XML ...
- 19 01 16 djano 视图以及url
视图 后台管理页面做好了,接下来就要做公共访问的页面了.当我们刚刚在浏览器中输入 http://127.0.0.1:8000/admin/ 之后,浏览器显示出了后台管理的登录页面,那有没有同学想过这个 ...
- 一行python代码能写出啥?
1.一行代码启动一个Web服务 python -m SimpleHTTPServer 8080 # python2 python3 -m http.server 8080 # python3 2. ...
- Java基础知识点简记
此篇主要记录(搬运)的是Java中一些常见概念的理解,大致内容如下 final.finally.finalize的区别 Java的传值或者传引用的理解 重写Override和重载Overload的理解 ...
- 工程日记之HelloSlide(1):Swift自定义可视化组件的方法(继承UIView和在StoryBoard中设置)
需求描述 HelloSlide是把文本自动转化成幻灯片的软件,在幻灯片中我们有SmartArt:各种各样的几何形状,并且可以自定义大小和颜色,放在幻灯片不同的位置. 为了在我们的软件中实现类似的效果, ...
- npm全局权限设置 - Mac
网络上的常见方法 目前网络上常见的方法都是修改npm安装路径的权限 通过使用命令 npm config get prefix 得到npm的路径,结果大部分都是/usr/local.然后,很多方法都会要 ...
- ubuntu root用户下找不到环境变量解决办法
打开 gedit /root/.bashrc ,在文件的末尾添加: source /etc/profile 然后执行更新:source /root/.bashrc
- A4纸网页打印
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Aras Innovator Method集成Visual Studio
首先下载集成安装包: https://github.com/RazorleafLabs/Aras-Integration-to-Visual-Studio 解压文件包,找到Aras-Integrati ...
- MySQL中间件介绍
360 Atlas Atlas是由 Qihoo 360, Web平台部基础架构团队开发维护的一个基于MySQL协议的数据中间层项目.它是在mysql-proxy 0.8.2版本的基础上,对其进行了优化 ...
