Iawen's Blog

我喜欢这样自由的随手涂鸦, 因为我喜欢风......

1. 关于SHELL

Shell 是一个用 C 语言编写的程序, 它是用户使用 Linux 的桥梁。Shell 既是一种命令语言, 又是一种程序设计语言。
Shell 是指一种应用程序, 这个应用程序提供了一个界面, 用户通过这个界面访问操作系统内核的服务。

1.1 .bash_* files的执行顺序

顺序 配置文件 login shell non-login shell
1 /etc/profile
2 ~/.bash_profile
3 ~/.bashrc
4 ~/.bash_login
5 ~/.profile
6 ~/.bash_logout

1.2 常用快捷键

组合键 功能
Ctrl + u/k 从光标处向前 / 向后 删除指令串
Ctrl + a/e 让光标移动到整个指令串的最前面 / 最后面
Ctrl+v Ctrl+m 特殊字符: ^M
Ctrl + s 锁屏
Ctrl + q 恢复屏幕
Ctrl + m 就是 Enter
Ctrl + ? 删除整个命令
Ctrl + z 暂停目前的命令
Ctrl + r 搜索命令的历史记录
Ctrl + t 交换光标所在和前一个字符

1.3 PS1的参数说明

参数 说明
\d 可显示出 “星期月日” 的日期格式, 如: “MonFeb2”
\H 完整的主机名称。举例来说, 鸟哥的练习机为 “study.centos.vbird”
\h 仅取主机名称在第一个小数点之前的名字, 如鸟哥主机则为 “study” 后面省略
\t 显示时间, 为24小时格式的 “HH:MM:SS”
\T 显示时间, 为12小时格式的 “HH:MM:SS”
\A 显示时间, 为24小时格式的 “HH:MM”
@ 显示时间, 为12小时格式的 “am/pm” 样式
\u 目前使用者的帐号名称, 如 “dmtsai”
\v BASH的版本信息, 如鸟哥的测试主机版本为4.2.46(1)-release, 仅取 “4.2” 显示
\w 完整的工作目录名称, 由根目录写起的目录名称。但主文件夹会以~取代
\W 利用basename函数取得工作目录名称, 所以仅会列出最后一个目录名
# 下达的第几个指令
$ 提示字符, 如果是root时, 提示字符为#, 否则就是$啰~

1.4 属性测试

参数 说明
-e 是否存在
-f 是否为文件
-d 是否为目录
-b 是否为 Block Device 设备
-c 是否为 character device 设备
-S 是否为 Socket 文件
-p 是否为一个 FIFO 文件
-L 是否为一个链接文件
-r 是否具有 “可读” 的权限
-w 是否具有 “可写” 的权限
-x 是否具有 “可执行” 的权限
-u 是否具有 “SUID” 的权限
-g 是否具有 “SGID” 的权限
-G 文件存在并由有效组ID拥有
-k 是否具有 “Sticky bit” 的权限
-s 是否 “非空白文件”
-O 文件存在并由有效用户ID拥有
-t fd
file1 -ef file2 文件1和文件2是否具有相同的inode number
file1 -nt file2 file1比file2更新
file1 -ot file2 file1比file2更老

1.5 字符串比较

参数 说明
string 字符串是否为空
-n string 字符串长度大于0
-z string 字符串长度为0
= OR ==
!=
> 注意: 当>或<表达式运算符与test一起使用时, 必须用引号引起来(或用反斜杠)
<

1.6 整型比较

-eq, -ne, -le, -lt, -ge, -gt

1.7 特殊符号

符号 说明
$$ 当前Shell 的 Pid
$? 上个执行指令的返回值
« 结束的输入字符
2>&1 或 &>!
&& 或
$# 代表后接的参数个数
$@ 代表 “"\(1" "\)2” “$3"“之意, 每个变量是独立的
$* 代表 “"\(1c\)2c$3"“之意, 其中 c 为分隔字符, 默认为空白

2. shell 常用功能

2.1 在终端上显示颜色

2.1.1 字体颜色

reset = 0, black = 30, red = 31, green = 32, yellow = 33, blue = 34, magenta = 35, cyan = 36, and white = 37.

2.1.2 背景颜色

reset = 0, black = 40, red = 41, green = 42, yellow =43, blue = 44, magenta = 45, cyan = 46, and white=47

echo-e"\e[1;31mThisisredtext\e[0m"
echo-e"\e[1;42mThisisGreenBackground\e[0m"
# \e[       表示颜色的起始位置
# x;ym      表示颜色的代码
# \e[0m     表示颜色的结束位置

查看更多颜色值: man console_codes

2.2 字符切分

${}并不是专门为提取文件名或目录名的, 它的使用是变量的提取和替换等等操作, 它可以提取非常多的内容。

标志 说明
# 表示从左边算起第一个
## 表示从左边算起最后一个
% 表示从右边算起第一个, 即删除%右侧的通配符所匹配的字符串
%% 表示从右边算起最后一个
/ 替换
// 替换全部, 如: echo ${PATH//bin/BIN}
- 变量是否存在, 类似三元操作
:- 变量是否为空

换句话来说, %总是表示右边算起(取左, 文件名), #总是表示左边算起(取右, 扩展名)。
*: 表示要删除的内容, 对于#和##的情况, 它位于指定的字符(例子中的’/‘和’.’)的左边, 表于删除指定字符及其左边的内容;
单个%或#, 是非贪婪(non-greedy)的, 两个的%%或##则是贪婪(greedy)的
对于%和%%的情况, 它位于指定的字符(例子中的’/‘和’.’)的右边, 表示删除指定字符及其右边的内容。
这里的’‘的位置不能互换, 即不能把号放在#或##的右边, 反之亦然。

filename="sample.middle.jpg"
name=${filename%.*}
extension=${filename##*.}
echo $name $extension
sample.middle jpg

例如: ${var%%x*}表示找出从右边算起最后一个字符x, 并删除字符x及其右边的字符。
看到这里, 就可以知道, 其实该命令的用途非常广泛, 上面只是指针文件名和目录名的命名特性来进行提取的一些特例而已。

#获取变量值的长度: 
var=12345678901234567890
length=${#var}

3. 强大的Shell 命令

3.1 sed 命令

命令 说明
x 交换模式空间和保持空间的内容
h 把模式空间的内容复制到保持空间
H 把模式空间内容追加到保持空间
g 把保持空间内容复制到模式空间
G 把保持空间内容追加到模式空间
N 读取下一行数据并附加到模式空间
n 打印当前模式空间的内容
P 打印多行模式中的第一行
p 打印模式空间中的内容
D 删除多行模式中的第一行
d 删除模式空间中的内容

3.1.1 匹配第N个进行替换

示例文本内容:

aa
88
bb
88
88
cc
88
88
# 替换第一个88为--
sed '0,/88/s//--/' file
sed ':a;N;$!ba;s/88/--/' file

[解析] 这有两种方法,

  • 第一个是只匹配到第一个88为止, 然后替换那个88为–。
  • 第二个句子是通过循环把文本全部读进pattern space 然后只替换第一个。
# 替换第N[3]个88为--
sed '/88/{x;s/^/./;/^.{3}$/{x;s/./--/;x};x;}' file
sed ':a;N;$!ba;s/88/--/3' file

[解析]

  • 第一个命令叫打点记数法, 因为sed没有 var++ 之类的操作来记数。
  • 第二个命令和上面第一个其实是一样的原理, 全部读入文本后统一替换第3个匹配的内容。
# 替换最后一个匹配的88为--
sed ':a;/\n88/!{$s/88/--/;N;ba};P;D' file
sed ':a;N;$!ba;s/(.)88/\1--/' file

[解析]

  • 第一个命令, 没匹配到 /\n88/ 的内容就读取下一行, 然后 ba 跳转去开始处, 如果读取到88的行呢, 就执行后面的 P;D 组合, D也有循环功能, 一直把匹配 \n88 内容的第一行打印, 删除, 直到不匹配/\n88/(因为换行符已经被打印出去了, 所以不再会匹配到 \n88), 这时候才继续往下读, 如果又读到88的行, 那么又执行P;D循环, 同上操作。一直到匹配到最后一个88的行, 继续读取到末行时执行替换, N 因为没有下一行可读, 所以会自动中止命令, 因为没有 -n 参数会打印 pattern space 里的内容到屏幕, 所以就不会再执行后面的 ba 避免了死循环, 这样的用法只存在于 GNU sed , 大家注意。所以这整个流程只会替换最后一个88。
  • 第二个命令其实和上面的都一样, 也是全部读进 pattern space 里, 最后利用正则的贪婪替换掉最后一个88。

3.2 gawk 命令

  • Awk 程序结构: BEGIN, Body, END
  • BEGIN { awk-commands } 命令只在最开始、在 awk 执行 body 区域命令之前执行一次。
  • Body 区域的语法: /pattern/{action} 每次从输入文件读取一行就会执行一次
  • END { awk-commands } 在awk 执行完成所有操作后执行, 并且只执行一次

3.2.1 标记/变量说明:

标记/变量 说明
-F 字段分界符或FS变量
FS 字段分界符, 只能在BEGIN区域中使用, 可以是多个, 如: BEGIN{FS=”[,:%]”}
OFS 输出字段分隔符, 默认为空格
RS 记录分隔符(默认为换行符)
ORS 输出记录分隔符
NR 记录序号
NF 每条记录的字段数
OFMT 仅适用与NAWK和GAWK, 默认值是”%.6g”
FILENAME 当前处理的文件名
FNR 文件中的NR
+、-、++、– 一元操作符(++/–, 前置或后置的作用, 与C相同)
+、-、*、/、% 算术操作符
=、+=、-=、*=、/=、%= 赋值操作符
>、>=、<、 <=、==、!=、&&、|| 比较操作符
, ! 正则表达式操作符(匹配 / 不匹配)
关联数组 检测元素: if (index in array) ; 遍历数组: for (index in array) 删除: delete array[index] / delete array
多维数组
SUBSEP 下标分隔符
asort 数组排序, 排序后, 原始索引不存在。
可以使用: len=asort(item, newitem) 生成新的排序数组。
asorti 为索引排序, 生成一个保存索引值的数组: len=asorti(item, newitem)
printf 格式化输出,不受OFS和ORS影响, 只根据格式打印,s(字符串)、c(单字符)、d(数值)、e(指数)、f(浮点数)、g(由值决定是e OR f)、o(八进制)、x(十六进制)、%(百分号)
打印列宽度, 必须在%和格式化字符之间设置一个数字, -左对齐, 无则右对齐。
内置数值函数 int(n)、log(n)、sqrt(n)、exp(n)、sin(n)、cos(n)、atan2(n)、rand()、srand(n)
字符串函数 index, length, split, substr, [sub, gsub, math, tolower, toupper
处理参数 ARGC, ARGV, ARGIND
位操作 AND, OR, XOR, compl, lshift, rshift
系统函数 system, systime, strftime, getline

3.2.2 其他

awk 'BEGIN{RS="-\n"; FS="\n"; OFS=":"; ORS="\n--------\n"} {print $2, $3}' employee-change-fs-ofs.txt

4. Shell 脚本

4.1 内置命令: test(help test)

test expression # OR
[ expression ]

# 增强测试功能, 类似 test, 但增加了正则表达式:  string1 =~ regex
[[ expression ]]

# 针对整型的复合命令
(( ))

4.2 变量声明

declare -r TITLE="Page Title"
# r 意为 readonly,  这里是声明一个常量

d="$(ls -l foo.txt)"    # 返回命令的结果
e=$((5 * 7))            # 算术扩展

# Here Documents
# command << token
# text
# token
# <<- 将忽略行首的Tab(不是空格)
cat << _EOF_ 
this is Text
_EOF_

# local variable
function func1 {
    local foo
}

4.3 组合表达式

操作 test [[ ]] and (()) 例子
AND -a && if [ ! \( “$INT” -ge “$MIN_VAL” -a “$INT” -le “$MAX_VAL” \) ];
OR -o ||
NOT ! !