Shell笔记
Shell 笔记
概论
Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。Shell 既是一种命令语言,又是一种程序设计语言(解释性)。
- bash :Bourne Again shell ,Linux缺省的 shell
- dash :Debian Almquist Shell ,小巧,符合 POSIX 标准,比 bash 快
- sh :Bourne shell ,之前是 UNIX 最初使用的 shell ,用户交互很烂;后来变为了 bash 的符号链接,再后来变为了 dash 的符号链接
- zsh :
最强大的 Shell ,最好看的 Shell ,程序员必备的 Shell- oh my zsh 是 zsh 的一个配置管理框架
- login Shell VS nologin Shell
- login Shell 在启动时会加载
/etc/profile
、/etc/bashrc
、~/.bash_profile
、~/.bashrc
,该种方式会切换环境变量,即启动一个全新的环境 - nologin Shell 在启动时会加载
/etc/bashrc
、~/.bashrc
- login Shell 在启动时会加载
su - kon # login
su kon # nologin
- 脚本执行:
脚本通过路径执行时默认执行脚本为当前类型的 Shell 解释器,也可以通过命令显式指定 Shell 解释器,此时脚本是在子Shell中执行,还可以通过脚本内的 sha-bang (释伴)指定脚本执行所需的 Shell 解释器;优先级:显式 > sha-bang > 当前
#!/usr/bin/sh
上述3种方法都是通过子 Shell 执行,脚本中的
cd
不会改路径;可以通过.
或source
指定当前 Shell 执行,脚本中的cd
会改路径只有路径执行需要文件执行权限,其它方法都不需要
./test.sh # 指定当前 Shell 的同类 Shell 执行, cd 不会改路径
sh test.sh
. ./test.sh # 指定当前的 Shell 执行, cd 会改路径
source ./test.sh # 指定当前的 Shell 执行, cd 会改路径
sh -vx test.sh # 以调试方式执行,显示整个执行过程
sh -n test.sh # 检查语法
()
:在子 Shell 中执行- 退出当前 Shell
exit
- 查看 Shell 关键字/命令
type ls if [ ]
- 命令排序
;
两个命令都被执行&&
前者成功则后者执行,否则不执行||
前者失败则后者执行,否则不执行
ls && la || ll # ls 执行成功则 la 执行,否则 ll 执行
- Bash 中调用 Python 脚本
- 此处的
<<EOF
表示后续的输入作为子命令或子 Shell 的输入,直到遇到 EOF (也可以换成别的符号)为止,再返回到主 Shell
- 此处的
#!/usr/bin/bash
python <<EOF # 此处若使用 python <<-EOF 据说表示忽略EOF前的空格和TAB,但我试了一下 Ubuntu 20.04 好像不行
print("hello")
print("python")
EOF # 此处必须顶格
- Shell 快捷键
ctrl + a
:光标移到行首ctrl + e
:光标移到行尾ctrl + u
:从光标处删到行首ctrl + k
:从光标处删到行尾ctrl + r
:搜索命令历史ctrl + d
:EOF,直接输效果同 exit
- 前后台
- 命令 +
&
:使该命令的执行隐藏到后台 nohup
:即使退出依然持续执行该命令ctrl + z
:挂起进程jobs
:查看后台进程bg
:把进程调度到后台执行fg
:把后台进程调度到前台执行kill %num
:杀死当前 Shell 中作业号为 num 的进程
- 命令 +
- 捕捉信号
trap “echo !” HUP INT # trap "commands" signal-list
kill -l # 查看信号
# HUP 通知会话内的各个作业与控制终端不再关联,默认处理是终止收到该信号的进程
# INT 程序终止,ctrl+c
# QUIT 程序退出,类 INT ,但表示程序错误
# KILL 立即结束程序
# TSTP 停止程序运行,ctrl+z
重定向
>
覆盖>>
追加0
标准输入 stdin1
标准输出 stdout2
错误输出 stderrcat
+EOF
+ 重定向 一定程度可以取代简单的vim
# 输出
echo hello > test.txt # 等同与 echo hello 1> test.txt
aaa 2> test.txt
./hello.out &> test.txt # 等同于 ./hello.out > test.txt 2>&1
- 通配符
- 可参考 MySQL 笔记
*
:任意多个字符?
:任意一个字符[]
:任意其中一个字符{}
:集合
- 基本输出
echo
:可以用颜色和部分转义符printf
:类似C
变量&数组
- 自定义变量:在当前 Shell 生效
- 命名规范:
_
、字母、数字;首字符不能是数字;区分大小写 - 引用:
${}
- 作用域:当前的 Shell
- 注意赋值
=
两边不要留空格 - 删除变量
unset
- 命名规范:
x1=1 # 1是字符串,同x1="1"
echo $x1
x1=2
echo ${x1}
echo ${#x1} # 长度
echo "${x1}"
echo "\${x1}"
- 变量 IO
read -p "Please enter a string: " x1 # -p 提示信息
echo $x1
read x1 x2 x3 x4 # 一次读入多个变量,空格分割,回车结束
- 预定义变量
echo $* # 所有命令行参数
echo $@ # 所有命令行参数
echo $# # 命令行参数个数
echo $$ # 当前进程 pid
echo $? # 上一条命令返回值
echo $! # 上一个后台进程 pid
echo $0 # 位置变量`$num`:表示第 num 个命令行参数
echo $1 # 位置变量`$num`:表示第 num 个命令行参数
- 环境变量:类似全局变量,在当前 Shell 和子 Shell 中生效;在 Shell 编程中一般不用
export x1=1
x2=2
export x2
env # 查看环境变量
- 命令替换:将字符串中命令(注意不能是变量)的输出替换字符串;若输出有多行,会默认用空格替换换行
$()
- 反引号 ``
- 强弱引用
- 单引号
''
:强引用,引用的是字符串本身的值,所见即所得 - 双引号
""
:弱引用,字符串中的变量(通过变量引用)、命令(通过命令替换)及转义字符会被解析替换
- 单引号
变量删除
#
:从前往后删除,最短匹配##
:从前往后删除,最长匹配,贪婪匹配
url=www.zhangty15226.com echo ${url#*.} echo ${url##*.}
%
:从后往前删%%
:从后往前删除,最长匹配,贪婪匹配
echo ${url%.*} echo ${url%%.*}
变量替换
/
:从前往后替换,最短匹配;后一个/
接新值//
:从前往后替换,最长匹配,贪婪匹配;后一个/
接新值
echo ${url/w/W} echo ${url//w/W}
:-
或-
或:+
或+
:有定义不替换;无定义替换
echo ${url-aaa} unset url echo ${url-aaa}
:=
或=
:有定义不替换;无定义替换;同时赋值变量:?
或?
:有定义不替换;无定义报错
字符串切片
- 类似
substr
echo ${url:0:10}
- 类似
整数运算
expr
:会把字符串参数当做整数\*
:乘一般需要转义
$(())
或$[]
let
let x=1+1
浮点数运算
bc
echo "1.1*1.2"|bc
python/python3
echo "print 1.1*1.2"|python echo "print(1.1*1.2)"|python3
更自由的变量方式:
declare
数组:索引数组(列表),关联数组(字典)
- 索引数组切片同字符串
- 都尽量使用索引遍历
a=(a1 a2 a3)
b=(`b.txt`) # 一行一个值
d[0]=d1;d[1]=d2;d[2]=d3
echo ${a[1]}
echo ${a[*]} # 所有元素,同@
echo ${#a[*]} # 元素个数
echo ${!a[*]} # 索引
declare -A c=([c1]=val1 [c2]=val2 [c3]=val3) # 关联数组
条件测试&分支
test
或[]
- 括号内两端需要有空格,因为
[
和]
是命令 -a
与;-o
或
- 括号内两端需要有空格,因为
- 文件、数值、字符串
- 详见
man test
- 也可以使用 C 风格脚本进行数值比较
(())
- 详见
[[]]
与[]
[[]]
支持正则匹配=~
,[]
不支持[[]]
支持逻辑运算符&&
、||
、!
,[]
不支持
if-else
if exp ; then
dosomething
else if exp2 ; then
dosomething
else
dosomething
fi # 在 shell 中命令的结束基本都是反过来的相应关键字
case
case val in
const1)
dosomething;;
const2)
dosomething;;
const3)
dosomething;;
*)
dosomething;;
esac
for
for val in {1..10} # `seq 1 10` # `cat num.txt`
do
dosomething
done
for ((i=0;i<10;i++))
do
dosomething
done
while
while exp
do
dosomething
done
until
:为假执行
until exp
do
dosomething
done
文件
- 当前进程文件描述符:文件描述符是文件的索引,
rm
只是回收 inode num 和处理文件的 link count 等
ll /proc/$$/fd
- 打开关闭文件
exec 6<> test.txt # 6为文件描述符
exec 6<&-
管道
- 管道是 FIFO 文件,是一个强制互斥的环形缓冲区
- 允许两个进程以生产者-消费者模型进行通信,有最大长度
- 匿名管道
|
- 配合
grep/egrep
进行筛选,egrep
支持更多拓展元字符;详见man grep
- 配合
tee
进行复制;详见man tee
- 配合
ag
进行搜素 - 相关:
awk
一门语言,可用于统计过滤等;详见man awk
- 相关:
sed
流编辑器;详见man sed
- 配合
- 配合
命名管道
mkfifo fifotest # 创建名为 fifotest 的管道
file fifotest
函数
- 定义
fun(){
dosomething
}
function fun(){
dosomething
}
- 使用基本变量
local
- 使用位置变量传入参
- 返回值
- 通过
return
和退出状态码$?
,是一个unsigned char
- 通过
echo
和命令替换
- 通过
杂
expect
:自动化处理交互式命令的命令shift
:将位置变量左移,用于可变参数传参
个人总结
- Shell 的语法实在是灵活多样
非常繁琐 awk
和sed
的细节其实非常多,这里暂略感觉关键还是写好正则
参考
Shell笔记
http://example.com/2022/05/02/Shell笔记/