add shell

pull/1/head
wanglei 2020-08-07 21:40:37 +08:00
parent 829bc17bcb
commit 1fcdef61da
15 changed files with 728 additions and 0 deletions

View File

@ -0,0 +1,88 @@
在写项目相关的解释文档或者说明文档或者需求文档的时候经常需要列出项目代码的树状结构。tree命令就能很好的满足我们这个小小的需求
linux与mac中的tree都不是自带的需要自行安装。如果不会安装请自行google在linux或者mac中怎样安装软件即可。。。
## 1.最简单的方式
最简单的使用方式就是直接输入`tree`命令了
```
$ tree
.
├── get_user_order.sh
├── mr.py
├── test
│ ├── mr.py
│ ├── subtest
│ │ └── a.txt
│ └── zzz.sh
├── zzzfile
└── zzz.sh
2 directories, 7 files
```
会把当前目录中所有的文件夹以及文件都遍历出来。当然,大部分情况下我们还会有别的需求,请接着往下看。
## 2.-L选项
-L选项是我实际中使用最多的参数。因为很多情况下可能文件夹的层数非常多我不希望看到后面所有的文件夹这个时候用-L选项即可搞定。
```
$ tree -L 1
.
├── get_user_order.sh
├── mr.py
├── test
├── zzzfile
└── zzz.sh
1 directory, 4 files
```
-L后面跟一个数字比如现在指定为1表示最多看当前目录下一层目录。
## 3.-d选项
```
$ tree -d
.
└── test
└── subtest
2 directories
```
只看文件夹,不解释。
## 4.-I选项
实际中还经常想忽略某些内容,这个时候-I就派上了用场。
```
$ tree -I zzzfile
.
├── get_user_order.sh
├── mr.py
├── test
│ ├── mr.py
│ ├── subtest
│ │ └── a.txt
│ └── zzz.sh
└── zzz.sh
2 directories, 6 files
```
如果要忽略多个,也很简单
```
$ tree -I "zzzfile|a.txt"
.
├── get_user_order.sh
├── mr.py
├── test
│ ├── mr.py
│ ├── subtest
│ └── zzz.sh
└── zzz.sh
2 directories, 5 files
```

View File

@ -0,0 +1,97 @@
代码中免不了要进行各种数据计算。抛开科学计算不提普通的计算占地百分比同比环比等需求就很常见。linux shell中进行数字计算主要有如下几种方式
## 1.bc
bc是比较常用的linux计算工具了而且支持浮点运算
```
[webopa@namenode-backup expensive_user]$ a=`echo 1+1 | bc`
[webopa@namenode-backup expensive_user]$ echo $a
2
```
但是浮点数运算的精度问题,暂时还没明白什么情况:
```
[webopa@namenode-backup expensive_user]$ b=`echo "1.2*1.2" | bc`
[webopa@namenode-backup expensive_user]$ echo $b
1.4
[webopa@namenode-backup expensive_user]$ c=`echo "5.0/3.0" | bc`
[webopa@namenode-backup expensive_user]$ echo $c
1
[webopa@namenode-backup expensive_user]$ d=`echo "scale=2;5.0/3.0" | bc`
[webopa@namenode-backup expensive_user]$ echo $d
1.66
[webopa@namenode-backup expensive_user]$ e=`echo "scale=2;5.0/6.0" | bc`
[webopa@namenode-backup expensive_user]$ echo $e
.83
```
尤其最后一个这到底什么鬼小数点前的那个0跑哪里去了。。。
## 2.expr
不支持浮点数计算。这又是个大坑.而且要注意数字与运算符中的空格
```
[webopa@namenode-backup expensive_user]$ a=`expr 1+1`
[webopa@namenode-backup expensive_user]$ echo $a
1+1
[webopa@namenode-backup expensive_user]$ a=`expr 1 + 1`
[webopa@namenode-backup expensive_user]$ echo $a
2
[webopa@namenode-backup expensive_user]$ b=`expr 10 / 2`
[webopa@namenode-backup expensive_user]$ echo $b
5
```
## 3.$(())
同expr不支持浮点数运算
```
[webopa@namenode-backup expensive_user]$ a=$((1+1))
[webopa@namenode-backup expensive_user]$ echo $a
2
[webopa@namenode-backup expensive_user]$ b=$((1 + 3 ))
[webopa@namenode-backup expensive_user]$ echo $b
4
```
## 4.let
不支持浮点数运算,而且不支持直接输出,只能赋值
```
[webopa@namenode-backup expensive_user]$ let a=1+1
[webopa@namenode-backup expensive_user]$ echo $a
2
[webopa@namenode-backup expensive_user]$ let b=50/5
[webopa@namenode-backup expensive_user]$ echo $b
10
[webopa@namenode-backup expensive_user]$ let c=1.2*2
-bash: let: c=1.2*2: syntax error: invalid arithmetic operator (error token is ".2*2")
```
## 5.awk
普通的运算:
```
[webopa@namenode-backup expensive_user]$ a=`echo | awk '{print 1.0/2.0}'`
[webopa@namenode-backup expensive_user]$ echo $a
0.5
```
控制精度:
```
[webopa@namenode-backup expensive_user]$ b=`echo | awk '{printf("%.2f",1.0/2.0)}'`
[webopa@namenode-backup expensive_user]$ echo $b
0.50
```
传递参数:
```
[webopa@namenode-backup expensive_user]$ c=`echo | awk -v a=1 -v b=3 '{printf("%.4f",a/b)}'`
[webopa@namenode-backup expensive_user]$ echo $c
0.3333
```
综合来看还是awk最靠谱其他的方式都有这样那样的问题。所以我平时一般都用awk来搞数学计算。

View File

@ -0,0 +1,65 @@
## VIRTvirtual memory usage 虚拟内存
1、进程“需要的”虚拟内存大小包括进程使用的库、代码、数据等
2、假如进程申请100m的内存但实际只使用了10m那么它会增长100m而不是实际的使用量
## RESresident memory usage 常驻内存
1、进程当前使用的内存大小但不包括swap out
2、包含其他进程的共享
3、如果申请100m的内存实际使用10m它只增长10m与VIRT相反
4、关于库占用内存的情况它只统计加载的库文件所占内存大小
## SHRshared memory 共享内存
1、除了自身进程的共享内存也包括其他进程的共享内存
2、虽然进程只使用了几个共享库的函数但它包含了整个共享库的大小
3、计算某个进程所占的物理内存大小公式RES SHR
4、swap out后它将会降下来
## DATA
1、数据占用的内存。如果top没有显示按f键可以显示出来。
2、真正的该程序要求的数据空间是真正在运行中要使用的。
## top 运行中可以通过 top 的内部命令对进程的显示方式进行控制。内部命令如下:
s 改变画面更新频率
l 关闭或开启第一部分第一行 top 信息的表示
t 关闭或开启第一部分第二行 Tasks 和第三行 Cpus 信息的表示
m 关闭或开启第一部分第四行 Mem 和 第五行 Swap 信息的表示
N 以 PID 的大小的顺序排列表示进程列表
P 以 CPU 占用率大小的顺序排列进程列表
M 以内存占用率大小的顺序排列进程列表
h 显示帮助
n 设置在进程列表所显示进程的数量
q 退出 top
s 改变画面更新周期
## 序号 列名 含义
a PID 进程id
b PPID 父进程id
c RUSER Real user name
d UID 进程所有者的用户id
e USER 进程所有者的用户名
f GROUP 进程所有者的组名
g TTY 启动进程的终端名。不是从终端启动的进程则显示为 ?
h PR 优先级
i NI nice值。负值表示高优先级正值表示低优先级
j P 最后使用的CPU仅在多CPU环境下有意义
k %CPU 上次更新到现在的CPU时间占用百分比
l TIME 进程使用的CPU时间总计单位秒
m TIME+ 进程使用的CPU时间总计单位1/100秒
n %MEM 进程使用的物理内存百分比
o VIRT 进程使用的虚拟内存总量单位kb。VIRT=SWAP+RES
p SWAP 进程使用的虚拟内存中被换出的大小单位kb。
q RES 进程使用的、未被换出的物理内存大小单位kb。RES=CODE+DATA
r CODE 可执行代码占用的物理内存大小单位kb
s DATA 可执行代码以外的部分(数据段+栈)占用的物理内存大小单位kb
t SHR 共享内存大小单位kb
u nFLT 页面错误次数
v nDRT 最后一次写入到现在,被修改过的页面数。
w S 进程状态。D=不可中断的睡眠状态R=运行S=睡眠T=跟踪/停止Z=僵尸进程)
x COMMAND 命令名/命令行
y WCHAN 若该进程在睡眠,则显示睡眠中的系统函数名
z Flags 任务标志,参考 sched.h
默认情况下仅显示比较重要的 PID、USER、PR、NI、VIRT、RES、SHR、S、%CPU、%MEM、TIME+、COMMAND 列。可以通过下面的快捷键来更改显示内容。
通过 f 键可以选择显示的内容。按 f 键之后会显示列的列表,按 a-z 即可显示或隐藏对应的列,最后按回车键确定。
按 o 键可以改变列的显示顺序。按小写的 a-z 可以将相应的列向右移动,而大写的 A-Z 可以将相应的列向左移动。最后按回车键确定。
按大写的 F 或 O 键,然后按 a-z 可以将进程按照相应的列进行排序。而大写的 R 键可以将当前的排序倒转。

View File

@ -0,0 +1,14 @@
下来搜狐实验室一些新闻语料做分析,结果打开发现其他标签都正常,就$<content>$标签内容不正常全是乱码。因此估计十有八九是编码问题。上网找了下linux里怎么解决中文乱码的问题。
其实挺简单用iconv命令就可以轻松搞定。linux里默认的字符集编码方式是utf-8而下载的内容的编码格式应该是gbk所以用如下命令
```
cat news.allsites.1120806.txt | iconv -f gbk -t utf-8 -c | grep "<content>" >zzz
```
iconv命令就是将制定文件从一种编码方式换到另外一种一种编码。
-f,--from-code ,表示文本的原始编码方式
-t, --to-code 表示文本的输出编码方式
-c 表示在输出中忽略无效字符
最后再配合grep命令就将文本中的正文内容提取出来

View File

@ -0,0 +1,9 @@
新建文件或者保存文件时候很容易输入乱码字符导致最后生成的文件名中有各种奇怪符号。当文件名包含这些符号的时候我们就无法通过键盘输入文件名所以在终端下就不能直接利用rmmv等命令管理文件了。
但是我们知道每个文件都有一个i节点号我们可以考虑通过i节点号来管理文件。首先我们要取得文件的i节点号。通过简单的ls -i 命令就可以得到文件的i节点号。然后使用find命令将文件名传递给rm命令。
删除节点为xxx的乱码文件夹可以使用如下命令(代码经过测试,表示没有问题)
find ./ -inum xxx -print -exec rm {} -rf \;
注意\;前面的空格不能少,少了就会报错。

View File

@ -0,0 +1,22 @@
Linux 守护进程概述
Linux Daemon守护进程是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。它不需要用户输入就能运行而且提供某种服务不是对整个系统就是对某个用户程序提供服务。Linux系统的大多数服务器就是通过守护进程实现的。常见的守护进程包括系统日志进程syslogd、 web服务器httpd、邮件服务器sendmail和数据库服务器mysqld等。
守护进程一般在系统启动时开始运行除非强行终止否则直到系统关机都保持运行。守护进程经常以超级用户root权限运行因为它们要使用特殊的端口1-1024或访问某些特殊的资源。
一个守护进程的父进程是init进程因为它真正的父进程在fork出子进程后就先于子进程exit退出了所以它是一个由init继承的孤儿进程。守护进程是非交互式程序没有控制终端所以任何输出无论是向标准输出设备stdout还是标准出错设备stderr的输出都需要特殊处理。
工作原理
Linux 守护进程的工作模式是服务器/客户机Server/Client服务器在一个特定的端口上监听Listen等待客户连接连接成功后服务器和客户端通过端口进行数据通信。守护进程的工作就是打开一个端口并且监听Listen等待客户连接。如果客户端产生一个连接请求守护进程就创建Fork一个子服务器响应这个连接而主服务器继续监听其他的服务请求。
工作模式
Linux 守护进程有两种工作模式stand-alone模式和xinetd模式。
1.stand-alone模式
独立运行的守护进程由init负责管理所有独立运行守护进程的脚本在/etc/rc.d/init.d/目录下。独立运行的守护进程工作方式称作stand-alone是Unix传统的C/S模式的访问模式。服务器监听Listen在一个特点的端口上等待客户端的联机。如果客户端产生一个连接请求守护进程就创建Fork一个子服务器响应这个连接而主服务器继续监听。工作在stand-alone模式下的网络服务有route、gated、web服务器等。在Linux系统中通过stand-alone工作模式启动的服务由/etc/rc.d/下面对应的运行级别当中的符号链接启动。
2.xinetd模式
从守护进程的概念可以看出对于系统所要求的每一种服务都必须运行一个监听某个端口连接所发生的守护进程这意味着资源浪费。为了解决这个问题Linux引进了"网络守护进程服务程序"的概念。Redhat Linux使用的网络守护进程是xintedeXtended InterNET Daemon。和standalone模式相比xinetd模式也称 InternetSuper-Server超级服务器。xinetd能够同时监听多个指定的端口在接受用户请求时他能够根据用户请求的端口不同启动不同的网络服务进程来处理这些用户请求。可以把xinetd看做一个管理启动服务的管理服务器它决定把一个客户请求交给那个程序处理然后启动相应的守护进程。
和stand-alone工作模式相比系统不必为每一个网络服务进程监听其服务端口运行xinetd守护进程就可以同时监听所有服务端口这样就降低了系统开销保护系统资源。但是对于访问量大、经常出现并发访问时xinetd想要频繁启动对应的网络服务进程反而会导致系统性能下降。一般来说系统一些负载高的服务比如Apache、sendmail等服务是单独启动的。而其他服务类型都可以使用xinetd超级服务器管理。
查看系统为Linux服务提供那种模式方法在Linux命令行可以使用pstree命令可以看到两种不同方式启动的网络服务。

View File

@ -0,0 +1,12 @@
统计文件夹下的文件个数(当前目录与子目录)
```
find ./ -type f | wc -l
ls -lR | grep "^-" | wc -l
```
如果只是查找当前文件夹不递归
```
find . -maxdepth 1 -type d | wc -l
```

View File

@ -0,0 +1,118 @@
## 求字符串长度:
```
$ x="a:b:c:"
方法一:
$ echo ${#x}
6
```
```
方法二用expr命令
$ expr length $x
6
```
PS:expr属于外部命令一般来说外部命令比内部命令要慢很多
```
$ time for i in $(seq 1 10000);do len=${#x};done
real    0m0.087s
user    0m0.081s
sys    0m0.001s
```
```
$ time for i in $(seq 1 10000);do len=$(expr length $x);done
real    0m13.313s
user    0m2.578s
sys    0m9.982s
```
## 字符串拼接
```
$ echo $x"ddd"
a:b:c:ddd
```
## 查找字符串位置
返回的索引是从1开始, 失败则返回0
```
$ expr index $x "a"
1
$ expr index $x "c"
5
expr index $x "d"
0
```
得到子字符串
```
方法一:${x:pos:length},本人一般用这种方式,嘻嘻
$ echo ${x:0:4}
a:b:
$ echo ${x:0}
a:b:c:
$ echo ${x:2}
b:c:
方法二: expr substr <string> startpos length
$ expr substr "$x" 1 2
a:
$ expr substr "$x" 1 10
a:b:c:
```
字符串替换
非贪婪模式
```
$ echo ${x/a/b}
b:b:c:
```
贪婪模式
```
$ xx="aaaaaa"
$ echo ${xx//a/b}
bbbbbb
```
## 处理字符串的头尾
```
$ zzz="this is a test"
```
\# 表示去掉头,一个为非贪婪模式,两个为贪婪模式
```
$ echo ${zzz#t}
his is a test
$ echo ${zzz#t*h}
is is a test
$ echo ${zzz##t*s}
t
```
%表示去掉尾,一个为非贪婪模式,两个为贪婪模式
```
$ echo ${zzz%t}
this is a tes
$ echo ${zzz%s*t}
this is a te
$ echo ${zzz%e*t}
this is a t
$ echo ${zzz%%s*t}
thi
```
去掉字符串最后一个字符
```
$ x='a:b:c:'
$ echo ${x%?}
a:b:c
```

View File

@ -0,0 +1,26 @@
有时候需要将sql查询封装在shell脚本中然后将查询结果导出存入文本后续再做进一步处理。对于这种常见需求特意做了个实例代码已经通过测试同学们可以大胆使用。
```
#!/bin/bash
host=xxx
user=xxx
password=xxx
port=xxx
dbname=xxx
sql_conn_str="-h${host} -P${port} -u${user} -p${password} $dbname"
function select_from_mysql()
{
sql="xxxxxx"
echo "$sql" | mysql -s $sql_conn_str >resultfile
}
select_from_mysql
```
上面的代码就可以满足我们的需求。注意的几个小点:
1.实际使用时候将数据库各配置项以及具体的sql查询语句替换成实际配置项即可。
2.mysql -s选项表示查询输出的结果不带字段名称如果不加-s选项会输出字段名称。
3.将resultfile换成你最终结果文件存储的地址。

View File

@ -0,0 +1,26 @@
做性能测试的时候,经常需要得到程序运行时间。
写了个简答的shell脚本供同学们参考。
```
#!/bin/bash
function handle()
{
start=$(date +%s%N)
start_ms=${start:0:16}
awk '{a[$1]++} END{print length(a)}' breakfast_all receptions_all cheap_all
end=$(date +%s%N)
end_ms=${end:0:16}
echo "cost time is:"
echo "scale=6;($end_ms - $start_ms)/1000000" | bc
}
handle
```
代码思路比较清晰 %s是精确到秒%N是纳秒取字符串前16位得到的是秒后小数点六位。再除以1000000最终的结果为以s为单位精确到小数点后6位。
需要不同的精度,调整字符串截取的位数即可。

View File

@ -0,0 +1,39 @@
## 1.问题描述
新安装的ubuntu18系统自己下载的软件包安装好以后无法将启动图标固定在dock栏上导致每次启动都要去软件安装的目录中执行对应的启动脚本非常不方便。为了解决上述问题可以采用如下解决方案。
## 2.解决办法
以pycharm为例
在`~/.local/share/applications`目录中新建pycharm.desktop文件
```
[Desktop Entry]
Encoding=UTF-8
Name=PyCharm
Exec=.../soft/pycharm-community-2020.1.1/bin/pycharm.sh
Icon=.../soft/pycharm-community-2020.1.1/bin/pycharm.svg
Terminal=false
Type=Application
Categories=Development
```
对应的Exec是pycharm的启动脚本位置Icon是对应的图标位置。
添加完上述文件以后点击左下角的“显示应用程序”然后找到pycharm的图标右击选择添加到收藏夹即可。
## 3. 消除侧边栏出现两个图标
启动时,侧边栏会出现两个图标,体验还是很差的。
具体的解决方案:
在terminate中执行`xprop |grep WM_CLASS`此时鼠标会变成一个十字的准星。此时点击已经打开的pycharm界面会出现如下内容
`WM_CLASS(STRING) = "jetbrains-pycharm-ce", "jetbrains-pycharm-ce"`
然后在pycharm.desktop后面添加一行
`StartupWMClass=jetbrains-pycharm-ce`
即可。

View File

@ -0,0 +1,70 @@
批量重命名文件名是常见的需求。例如我们这有三个文件都是以.txt结尾现在我们想重命名为.csv文件。以下给同学们介绍如下两种方式。
## 1.使用mv命令
话不多少,直接上代码
```
#!/bin/bash
for file in `ls`
do
newfile=`echo $file | sed 's/\.txt/\.csv/'`
mv $file $newfile
done
```
mv的方式如上。如果不是修改后缀而是其他方式修改后面sed的正则表达方式即可。
## 2.使用rename命令
```
rename .txt .csv *
```
rename 命令可能实际中用得不如mv多。rename最大的好处就是可以同时处理多个文件。来看看rename的用法
```
RENAME(1) Linux Programmers Manual RENAME(1)
NAME
rename - Rename files
SYNOPSIS
rename from to file...
rename -V
DESCRIPTION
rename will rename the specified files by replacing the first occurrence of from in their name by to.
-V, --version
Display version information and exit.
For example, given the files
foo1, ..., foo9, foo10, ..., foo278, the commands
rename foo foo0 foo?
rename foo foo0 foo??
will turn them into foo001, ..., foo009, foo010, ..., foo278.
And
rename .htm .html *.htm
will fix the extension of your html files.
SEE ALSO
mmv(1), mv(1)
AVAILABILITY
The rename command is part of the util-linux-ng package and is available from ftp://ftp.kernel.org/pub/linux/utils/util-linux-ng/.
1 January 2000 RENAME(1)
```
需要注意的是rename使用时需要有三个参数。而且注意一下rename的通配符
```
? 可替代单个字符
* 可替代多个字符
* [charset] 可替代charset集中的任意单个字符
```

View File

@ -0,0 +1,73 @@
这八个建议,来源于键者几年来编写 shell 脚本的一些经验和教训。事实上开始写的时候还不止这几条,后来思索再三,去掉几条无关痛痒的,最后剩下八条。毫不夸张地说,每条都是精挑细选的,虽然有几点算是老生常谈了。
## 1. 指定bash
shell 脚本的第一行,#!之后应该是什么?如果拿这个问题去问别人,不同的人的回答可能各不相同。
我见过/usr/bin/env bash也见过/bin/bash还有/usr/bin/bash还有/bin/sh还有/usr/bin/env sh。这算是编程界的“'茴'字四种写法”了。
在多数情况下,以上五种写法都是等价的。但是,写过程序的人都知道:“少数情况”里往往隐藏着意想不到的坑。
如果系统的默认 shell 不是 bash 怎么办?比如某 Linux 发行版的某个版本,默认的 sh 就不是 bash。
如果系统的 bash 不是在 /usr/bin/bash 怎么办?
我推荐使用 /usr/bin/env bash 和 /bin/bash。前者通过env添加一个中间层让env在$PATH中搜索bash后者则是官方背书的约定俗成的 bash 位置,/usr/bin/bash不过是指向它的一个符号链接。
## 2. set -e 和 set -x
OK经过一番讨论现在第一行定下来了。接下来该开始写第二行了吧
且慢在你开始构思并写下具体的代码逻辑之前先插入一行set -e和一行set -x。
set -x会在执行每一行 shell 脚本时,把执行的内容输出来。它可以让你看到当前执行的情况,里面涉及的变量也会被替换成实际的值。
set -e会在执行出错时结束程序就像其他语言中的“抛出异常”一样。准确说不是所有出错的时候都会结束程序见下面的注
set -e结束程序的条件比较复杂在man bash里面足足用了一段话描述各种情景。大多数执行都会在出错时退出除非 shell 命令位于以下情况:
一个 pipeline 的非结尾部分,比如 error | ok
一个组合语句的非结尾部分,比如 ok && error || other
一连串语句的非结尾部分,比如 error; ok
位于判断语句内包括test、if、while等等。
这两个组合在一起用,可以在 debug 的时候替你节省许多时间。出于防御性编程的考虑,有必要在写第一行具体的代码之前就插入它们。扪心自问,写代码的时候能够一次写对的次数有多少?大多数代码,在提交之前,通常都经历过反复调试修改的过程。与其在焦头烂额之际才引入这两个配置,不如一开始就给 debug 留下余地。在代码终于可以提交之后,再考虑是否保留它们也不迟。
## 3. 带上shellcheck
好了,现在我已经有了三行(样板)代码,具体的业务逻辑一行都没写呢。是不是该开始写了?
且慢!工欲善其事,必先利其器。这次,我就介绍一个 shell 脚本编写神器shellcheck
说来惭愧,虽然写了几年 shell 脚本,有些语法我还是记不清楚。这时候就要依仗 shellcheck 指点一下了。shellcheck 除了可以提醒语法问题以外,还能检查出 shell 脚本编写常见的 bad code。本来我的N条建议里面还有几条是关于这些 bad code 的,不过考虑到 shellcheck 完全可以发掘出这些问题,于是忍痛把它们都剔除在外了。毫无疑问,使用 shellcheck 给我的 shell 编写技能带来了巨大的飞跃。
所谓“站在巨人的肩膀上”,虽然我们这些新兵蛋子,技能不如老兵们强,但是我们可以在装备上赶上对方啊!动动手安装一下,就能结识一个循循善诱的“老师”,何乐而不为?
顺便一提shellcheck 居然是用 haskell 写的。谁说 haskell 只能用来装逼?
## 4. 变量展开
在 shell 脚本中偶尔可以看到这样的做法echo $xxx | awk/sed/grep/cut... 。看起来大张形势的样子其实不过是想修改一个变量的值。杀鸡何必用牛刀bash内建的变量展开机制已经足以满足你各种需求还是老方法 read the f**k manaul! man bash 然后搜索Parameter Expansion下面就是你想要的技巧。键者也写过一篇相关的文章希望能助上一臂之力玩转Bash变量
## 5. 注意local
随着代码越写越多你开始把重复的逻辑提炼成函数。有可能你会掉到bash的一个坑里。在bash如果不加 local 限定词,变量默认都是全局的。变量默认全局——这跟 js 和 lua 相似;但相较而言,很少有 bash 教程一开始就告知你这个事实。在顶级作用域里,是否是全局变量并不重要。但是在函数里面,声明一个全局变量可能会污染到其他作用域(尤其在你根本没有注意到这一点的情况下)。所以,对于在函数内声明的变量,请务必记得加上 local 限定词。
## 6. trap信号
如果你写过稍微复杂点的在后台运行的程序,应该知道 posix 标准里面“信号”是什么一回事。如果不知道直接看下一段。像其他语言一样shell 也支持处理信号。trap sighandler INT可以在接收到 SIGINT 时调用 sighandler 函数。捕获其他信号的方式以此类推。
不过 trap 的主要应用场景可不是捕获哪个信号。trap 命令支持“捕获”许多不同的流程——准确来说允许用户给特定的流程注入函数调用。其中最为常用的是trap func EXIT和trap func ERR。
trap func EXIT允许在脚本结束时调用函数。由于无论正常退出抑或异常退出所注册的函数都能得以调用在需要调用一个清理函数的场景下我都是用它注册清理函数而不是简单地在脚本结尾调用清理函数。
trap func ERR允许在运行出错时调用函数。一个常用的技法是使用全局变量ERROR存储错误信息然后在注册的函数中根据存储的值完成对应的错误报告。把原本四分五裂的错误处理逻辑集中到一处有时候会起奇效。不过要记住程序异常退出时既会调用EXIT注册的函数也会调用ERR注册的函数。
## 7. 三思后行
以上几条都是具体的建议,剩下两条比较务虚。
这条建议的名字叫“三思而行”。其实无论写什么代码,哪怕只是一个辅助脚本,都要三思而行,切忌粗心大意。不,写脚本的时候更要记住这点。毕竟许多时候,一个复杂的脚本发端于几行小小的命令。一开始写这个脚本的人,也许以为它只是一次性任务。代码里难免对一些外部条件有些假定,在当时也许是正常的,但是随着外部环境的变化,这些就成了隐藏的暗礁。雪上加霜的是,几乎没有人会给脚本做测试。除非你去运行它,否则不知道它是否还能正常使用。
要想减缓脚本代码的腐烂速度,需要在编写的时候辨清哪些是会变的依赖、哪些是脚本正常运行所不可或缺的。要有适当的抽象,编写可变更的代码;同时要有防御性编程的意识,给自己的代码一道护城河。
## 8. 扬长避短
有些时候,使用 shell 写脚本就意味着难以移植、难以统一地进行错误处理、难以利索地处理数据。
虽然使用外部的命令可以方便快捷地实现各种复杂的功能但作为硬币的反面不得不依靠grep、sed、awk等各种工具把它们粘合在一起。
如果有兼容多平台的需求还得小心规避诸如BSD和GNU coreutilsbash版本差异之类奇奇怪怪的陷阱。
由于缺乏完善的数据结构以及一致的APIshell 脚本在处理复杂的逻辑上力不从心。
解决特定的问题要用合适的工具。知道什么时候用 shell什么时候切换到另外一门更通用的脚本语言比如ruby/python/perl这也是编写可靠 shell 脚本的诀窍。如果你的任务可以组合常见的命令来完成,而且只涉及简单的数据,那么 shell 脚本就是适合的锤子。如果你的任务包含较为复杂的逻辑而且数据结构复杂那么你需要用ruby/python之类的语言编写脚本。
PS文中提到的几个点博主在平时实践中也有所体会。没有找到原文的原始出处所以没有给出原始链接。

View File

@ -0,0 +1,61 @@
## 1.打开/前往
⌘T 前往文件
⌘⌃P 前往项目
⌘R 前往 method
⌘⇧P 命令提示
⌃G 前往行
⌘KB 开关侧栏
⌃ ` python 控制台
⌘⇧N 新建窗口
## 编辑
⌘L 选择行 (重复按下将下一行加入选择)
⌘D 选择词 (重复按下时多重选择相同的词进行多重编辑)
⌃⇧M 选择括号内的内容
⌘⇧↩ 在当前行前插入新行
⌘↩ 在当前行后插入新行
⌃⇧K 删除行
⌘KK 从光标处删除至行尾
⌘K⌫ 从光标处删除至行首
⌘⇧D 复制(多)行
⌘J 合并(多)行
⌘KU 改为大写
⌘KL 改为小写
⌘ / 注释
⌘⌥ / 块注释
⌘Y 恢复或重复
⌘⇧V 粘贴并自动缩进
⌃ space 自动完成(重复按下选择下一个提示)
⌃M 跳转至对应的括号
⌘U 软撤销(可撤销光标移动)
⌘⇧U 软重做(可重做光标移动)
XML/HTML
⌘⇧A 选择标签内的内容
⌘⌥ . 闭合当前标签
## 查找/替换
⌘F 查找
⌘⌥F 替换
⌘⌥G 查找下一个符合当前所选的内容
⌘⌃G 查找所有符合当前所选的内容进行多重编辑
⌘⇧F 在所有打开的文件中进行查找
## 拆分窗口/标签页
⌘⌥1 单列
⌘⌥2 双列
⌘⌥5 网格 (4组)
⌃[1,2,3,4] 焦点移动至相应组
⌃⇧[1,2,3,4] 将当前文件移动至相应组
⌘[1,2,3…] 选择相应标签页
## 书签
⌘F2 添加/去除书签
F2 下一个书签
⇧F2 前一个书签
⌘⇧F2 清除书签
## 标记
⌘K space 设置标记
⌘KW 从光标位置删除至标记
⌘KA 从光标位置选择至标记
⌘KG 清除标记

View File

@ -0,0 +1,8 @@
mac中sublime全部查找替换的快捷键为option + cmd + f
现在要想批量在行首添加注释,可以有以下操作:
先按option + cmd + f在find what中输入 ^,查找到所有的行首,然后就可以在行首批量添加。
同理,要想在行末批量添加,
先按option + cmd + f在find what中输入 $,查找到所有的行尾,然后就可以在行尾批量添加。
需要注意的是以上操作需要将左下方的Regular expression激活因为^,$是正则表达式的写法