什么是 shell
shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。
shell 对用户输入的命令进行解析,然后传递给 Linux 内核,因此它被称为命令解释器
将 shell 从 Linux 内核分离,避免 shell 的错误对 Linux 内核造成影响
第一个 shell 脚本
1 2
| #!/bin/bash echo 'Hello world'
|
touch一个 bash 文件后
1 2
| chomod +x hello.sh ./hello.sh:
|
1 2 3 4
| #!/bin/bahs echo \ 'Hello world' \ 'GOOD'
|
变量
1 2 3 4 5
| #!/bin/bash pen='Hello world' item=pen echo I have a $pem echo I have many ${item}s
|
环境变量
环境变量用于保存一些可以在不修改程序自身代码的情况下,控制命令内部执行的配置参数。
设置环境变量
1 2 3 4 5
| #!/bin/bash
CONFIG_FILE=/root/conf.txt export CONFIG_FILE bash conf.sh
|
在 conf.sh 中
1 2 3
| #!/bin/bash
echo $CONFIG_FILE
|
特殊的 shell 变量
HOME:保存当前登录用户的用户主目录的
PWD:当前目录
SHELL:当前登录用户的登录 shell 的全路径
BASH:保存了 bash 命令的全路径
BASH_VERSION:保持了当前 bash 命令的版本信息
LINENO:保存了当前所执行的脚本文件的行号
LANG:国家语言信息
PATH:保存了 shell 启动命令时的目录
IFS:Internal Field Separator (内部字段分割符)
位置参数
用于读取命令行参数的变量
1 2 3 4 5 6
| #!/bin/bash echo arg1:$1 echo arg2:$2 echo arg3:$3 echo all:$* echo all:$@
|
特殊参数
| 变量名 |
说明 |
| $# |
位置参数的个数 |
| $? |
上一条命令的 |
| $$ |
当前进程的进程 ID |
| $! |
最后启动的后台命令的进程 ID |
使用 declare 声明变量
| 选项 |
属性 |
| -r |
声明只读变量 |
| -i |
声明的变量为整型 |
| -a |
声明的变量为数组 |
| -A |
声明的变量为关联数组 |
数组
1 2 3
| fruite=(apple grape orange peach) list =() declare -a arr1
|
访问数组
1 2 3 4 5 6 7
| $ fruite=(apple grape orange peach) $ echo ${fruite[0]} apple $ echo ${fruite} apple $ echo ${#fruite[@]} 4
|
使用索引进行赋值
1 2 3 4 5 6 7 8 9 10
| #!/bin/bash fruite=(apple [2]=grape [5]=orange [8]=peach) fruite[1]=banana echo num ${#fruite[@]} echo ${fruite[0]} echo ${fruite[1]} echo ${fruite[2]} echo ${fruite[3]} echo ${fruite[4]} echo ${fruite[5]}
|
删除数组
1 2 3 4
| #!/bin/bash fruite=(apple [2]=grape [5]=orange [8]=peach) unset fruite[2] echo ${fruite[@]}
|
访问所有数组
1 2 3 4
| #!/bin/bash fruite=(apple grape orange peach) echo echo ${fruite[@]} echo echo ${fruite[*]}
|
添加元素
1 2 3 4 5 6 7
| #!/bin/bash fruite=(apple grape orange peach) echo ${fruite[@]} fruite=(banana "${fruite[@]}" ) echo ${fruite[@]} fruite=("${fruite[@]}" coco) echo ${fruite[@]}
|
获取元素的索引列表
1 2 3
| #!/bin/bash fruite=(apple grape orange peach) echo ${!fruite[@]}
|
关联数组
一种键值对的数据结构
1 2
| declare -A user user=([id]=2021 [name]=miyake)
|
关联数组必须使用 declare 进行声明
访问数组元素
1 2 3 4 5
| #!/bin/bash declare -A user=([id]=2021 [name]=harsh) echo ${user[id]} echo ${user[name]} echo ${#user[@]}
|
赋值
1 2 3 4
| #!/bin/bash declare -A user=([id]=2021 [name]=harsh) user[id]=2022 echo ${user[id]}
|
删除
1 2 3
| #!/bin/bash declare -A user=([id]=2021 [name]=harsh) unset user[id]
|
获取所有的值
获取关联数组中的键的列表
展开和引用
路径展开
| 符号 |
含义 |
| ? |
任意一个字符 |
| * |
任意字符串 |
| [ ] |
[] 中包含的任意一个字符 |
| [!] 或 [^] |
任意一个不在 [] 的字符 |
1 2 3
| ls main.? ls *.sh ls file[1-4].txt
|
大括号展开
{字符串 1,字符串 2,字符串 3}
1
| mkdir work/{src,log,tets}
|
{开始值… 结束值}
1 2
| echo file-{8..11}.txt echo file-{8..11..2}.txt
|
波浪线展开
用于指定用户主目录的方法
在字符串~ 用户名,则展开为指定用户的主目录。如果省略,则展开为当前登录用户的主目录。
参数展开
使用:-进行展开
:-根据指定的值是是否被赋值来决定要展开的值
1 2 3 4
| echo ${name:-harsh} name=bill echo ${name:-harsh} echo ${config_file:-$HOME/.conf}
|
历史命令展开
| 符号 |
说明 |
| ! |
开始历史记录替换 |
| !n |
获取第 n 条命令行 |
| !-n |
获取当前命令往前的第 nt 条命令 |
| !! |
获取上一条命令 |
| !string |
获取以 string 开头的最后执行的命令 |
| !?string? |
获取包含 string 的最后执行的命令 |
| ^string^string2^ |
将 string1 替换为 string2 后重复执行最后的命令 |
| !# |
目前输入的所有命令行 |
引用
使用\进行引用
1 2 3
| echo \* eecho \$ echo \\
|
使用'和"进行引用
单引号全部称为字符串
双引号中,$、\和`保留转义
控制结构
If
1 2 3 4 5 6 7
| if 条件;then
elif 条件;then
else
fi
|
1 2 3 4 5 6
| #!/bin/bash if cd "$1";then echo success else echo fail fi
|
test 命令
1 2 3
| answer=yes [ "$answer"=yes ] echo $?
|
for
1 2 3 4
| for 变量 in 单词列表 do 循环处理 done
|
case
1 2 3 4 5 6 7 8
| case 字符串 in 模式1) ;; 模式2)
;; esac
|
while
until 命令
do
done
重定向和管道
重定向
输出的重定向
| 名称 |
文件描述符 |
| 标准输入 |
0 |
| 标准输出 |
1 |
| 标准错误输出 |
2 |
输入的重定向
重定向和追加写入
1 2
| echo line1>>word.txt echo line2>>word.txt
|
标准统一输出和标准输出
1
| ls /usr/xxx >result.txt 2> error.txt
|
将标准输出和标准错误输出定向到同一个文件
1
| ls /usr/xxx >result.txt 2>&1
|
管道
命令分组
1 2 3 4 5 6
| { date +%Y-%m-%d echo '/usr list ' ls /usr } >result.txt {date +%Y-%m-%d;echo '/usr list ';ls /usr;} >result.txt
|
函数
1 2 3 4 5 6 7 8 9
| function 函数名(){ } function 函数名{ } 函数名{ }
|