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"|bcpython/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;;
esacfor
for val in {1..10} # `seq 1 10` # `cat num.txt`
do
dosomething
done
for ((i=0;i<10;i++))
do
dosomething
donewhile
while exp
do
dosomething
doneuntil:为假执行
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笔记/