# Bash
# 学习资料
阮一峰 Bash 脚本教程 (opens new window)
# Shell 和 Bash
Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。Shell 既是一种命令语言,又是一种程序设计语言。
Shell 也指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。
# Bash 简介
Bash 是 Unix 系统和 Linux 系统的一种 Shell(命令行环境),是目前绝大多数 Linux 发行版的默认 Shell。
# Shell 的含义
首先,Shell 是一个程序,提供一个与用户对话的环境。这个环境只有一个命令提示符,让用户从键盘输入命令,所以又称为命令行环境
其次,Shell 是一个命令解释器,解释用户输入的命令。它支持变量、条件判断、循环操作等语法,所以用户可以用 Shell 命令写出各种小程序,又称为脚本
最后,Shell 是一个工具箱,提供了各种小工具,供用户方便地使用操作系统的功能。
# Shell 和 Bash 的历史
1969 年,Ken Thompson 和 Dennis Ritchie 开发了第一版的 Unix。
1971 年,Ken Thompson 编写了最初的 Shell,称为 Thompson shell。
1973 年至 1975 年间,John R. Mashey 扩展了最初的 Thompson shel, 称为 Mashey shell。
1976 年,Stephen Bourne 结合 Mashey shell 的功能,重写一个新的 Shell,称为 Bourne shell。
1979 年,UNIX 第七版发布,内置了 Bourne Shell,导致它成为 Unix 的默认 Shell。
1985 年,Richard Stallman 成立了自由软件基金会(FSF)
1988 年,自由软件基金会的第一个付薪程序员 Brian Fox 写了一个 Shell,功能基本上是 Bourne shell 的克隆,叫做 Bourne-Again SHell,简称 Bash
1989 年,Bash 发布 1.0 版。
1996 年,Bash 发布 2.0 版。
2004 年,Bash 发布 3.0 版。
2009 年,Bash 发布 4.0 版。
2019 年,Bash 发布 5.0 版。
GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
# Bash 的基本语法
# echo 命令
echo 命令的作用是在屏幕输出一行文本,可以将该命令的参数原样输出。
$ echo hello world
hello world
使用#! 指定执行的 shell 类型
#!/bin/bash
echo "Hello World !"
-e
-e
参数会解释引号(双引号和单引号)里面的特殊字符(比如换行符\n)
$ echo "Hello\nWorld"
Hello\nWorld
# 双引号的情况
$ echo -e "Hello\nWorld"
Hello
World
# 命令格式
命令行环境中,主要通过使用 Shell 命令,进行各种操作。Shell 命令基本都是下面的格式。
$ command [ arg1 ... [ argN ]]
# 比如
$ ls -l
Bash 单个命令一般都是一行,用户按下回车键,就开始执行。有些命令比较长,写成多行会有利于阅读和编辑,这时可以在每一行的结尾加上反斜杠
$ echo foo bar
# 等同于
$ echo foo \
bar
空格
Bash 使用空格(或 Tab 键)区分不同的参数。如果参数之间有多个空格,Bash 会自动忽略多余的空格。
$ echo this is a test
this is a test
分号 分号(;)是命令的结束符
clear; ls
除了分号,Bash 还提供两个命令组合符&&和||,允许更好地控制多个命令之间的继发关系。
组合符号
Command1 && Command2
上面命令的意思是,如果 Command1 命令运行成功,则继续运行 Command2 命令。
Command1 || Command2
上面命令的意思是,如果 Command1 命令运行失败,则继续运行 Command2 命令。
type 命令
$ type echo
echo is a shell builtin
$ type ls
ls is hashed (/bin/ls)
上面代码中,type 命令告诉我们,echo 是内部命令,ls 是外部程序(/bin/ls)。
# Bash 的模式扩展
Shell 接收到用户输入的命令以后,会根据空格将用户的输入,拆分成一个个词元(token)。然后,Shell 会扩展词元里面的特殊字符,扩展完成后才会调用相应的命令。
这种特殊字符的扩展,称为模式扩展(globbing)。
模式扩展与正则表达式的关系是,模式扩展早于正则表达式出现,可以看作是原始的正则表达式。它的功能没有正则那么强大灵活,但是优点是简单和方便。
# 波浪线扩展
波浪线~会自动扩展成当前用户的主目录。
$ echo ~
/root
~+会扩展成当前所在的目录,等同于 pwd 命令。
$ cd ~/foo
$ echo ~+
/home/me/foo
# ? 字符扩展
?字符代表文件路径里面的任意单个字符
# 存在文件 a.txt、b.txt 和 ab.txt
$ ls ??.txt
ab.txt
# * 字符扩展
*字符代表文件路径里面的任意数量的任意字符,包括零个字符。
# 存在文件 a.txt、b.txt 和 ab.txt
$ ls *.txt
a.txt b.txt ab.txt
# 方括号扩展
括号之中的任意一个字符。比如,[aeiou]可以匹配五个元音字母中的任意一个。
# 只存在文件 a.txt b.txt c.txt ab.txt
$ ls [ab].txt
a.txt b.txt
$ ls a?[b].txt
# Shell 数据类型
# 变量
# 定义变量
=
、
变量名不能有美元符号,因为 shell 使用$shell 来对变量取值和对命令取返回值
变量名和等号之间不能有空格
变量中间不能有空格,可以使用下划线
your_name="runoob.com"
for file in `ls /etc`
或
for file in $(ls /etc)
以上语句将 /etc 下目录的文件名循环出来。
# 使用变量 $
使用一个定义过的变量,在变量名前加美元符号,比如
your_name="qinjx"
echo $your_name
echo ${your_name}
变量名外面的花括号是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界,这里我还是选择使用${}
吧
# 二次赋值 =
your_name="tom"
echo $your_name
your_name="alibaba"
echo $your_name
# 只读变量 readonly
#!/bin/bash
myUrl="https://localhost"
readonly myUrl
myUrl="https://google.com"
# 运行结果
NAME: This variable is read only.
# 删除变量 unset
#! /bin/sh
myUrl="http://www.gausszhou.top"
echo $myUrl
unset myUrl
echo $myUrl
# 运行结果
http://www.gausszhou.top
# Shell 字符串
# 单引号
单引号内的任何字符都会原样输出,变量无效
str='this is a string'
# 双引号
双引号里可以有变量,可以出现转义字符
your_name="alice"
str="Hello, I know you are \"$your_name"\! \n"
echo -e $str
# 获取字符串长度 ${#}
string="abcd"
echo ${#string}
# 提取子字符串 ${str:start:count}
# 从第二个字符开始截取四个字符
string="ruboob is a great site"
echo ${string:1:4}
# 输出结果
unoo
# 查找字符串
# 查找i或o的位置
string="runoob is a great site"
echo `expr insex "$string" io`
# 输出
4
# Shell 数组
bash 支持一维数组,并且没有限制数组的大小
# 定义数组 ()
在 shell 中,用括号来表示数组,数组元素用“空格”符号来分隔,定义数组的一般形式为
# 数组=(值1 值2 ... 值n)
array_name=(val0 val1 val2)
array_name=(
val0,
val1,
val2
)
array_name[0]=val0
array_name[1]=val1
array_name[2]=val2
# 读取数组 []
读取数组的一般格式是
# ${数组名[下标]}
value=${array_name[n]}
# 使用@符号可以获取数组中的所有元素
echo ${array_name[@]}
# 获取数组长度 ${#}
length=${#array_name[@]}
length=${#array_name[*]}
# 获取数组中单个元素的长度
lengthn=${#array_name[n]}
# shell 注释
以#
开头的行就是注释,会被解释器忽略
# 这是注释
# 这也是注释
多行注释
:<<!
注释内容...
注释内容...
注释内容...
!
# Shell 传递参数
TIP
TODO
# Shell 流程控制
TIP
TODO