前文:VIM的用法


bash的基础特性:

一、

命令历史:shell进程会其会话中保存此前用户提交执行过的命令;

~]# history

定制history的功能,可通过环境变量实现:

HISTSIZE:shell进程可保留的命令历史的条数;

HISTFILE:持久保存命令历史的文件;

.bash_history

HISTFILESIZE:命令历史文件的大小;


命令用法:

history [-c] [-d 偏移量] [n] 

或 history -anrw [文件名] 

或 history -ps 参数 [参数...]


-c: 清空命令历史;

-d offset:删除指定命令历史

-r: 从文件读取命令历史至历史列表中;

-w:把历史列表中的命令追加至历史文件中;

history #:显示最近的#条命令;


调用命令历史列表中的命令:

!#:再一次执行历史列表中的第#条命令;

!!:再一次执行上一条命令;

!STRING:再一次执行命令历史列表中最近一个以STRING开头的命令;


注意:命令的重复执行有时候需要依赖于幂等性;


调用上一条命令的最后一个参数:

快捷键:ESC, .

字符串:!$


控制命令历史记录的方式:

环境变量:HISTCONTROL

ignoredups:忽略重复的命令;

ignorespace:忽略以空白字符开头的命令;

ignoreboth:以上两者同时生效;


修改变量的值:

NAME='VALUE'

二、命令补全:

shell程序在接收到用户执行命令的请求,分析完成之后,最左侧的字符串会被当作命令;

命令查找机制:

查找内部命令;

根据PATH环境变量中设定的目录,自左而右逐个搜索目录下的文件名;


给定的打头字符串如果能惟一标识某命令程序文件,则直接补全;

                    不能惟一标识某命令程序文件,再击tab键一次,会给出列表;


三、路径补全:

在给定的起始路径下,以对应路径下的打头字串来逐一匹配起始路径下的每个文件:

tab:

如果能惟一标识,则直接补全;

否则,再一次tab,给出列表;

四、命令行展开

~:自动展开为用户的家目录,或指定的用户的家目录;

{}:可承载一个以逗号分隔的路径列表,并能够将其展开为多个路径;

例如:/tmp/{a,b} 相当于 /tmp/a /tmp/b

五、命令的执行状态结果


命令执行的状态结果:

bash通过状态返回值来输出此结果:

成功:0

失败:1-255


命令执行完成之后,其状态返回值保存于bash的特殊变量$?中;


命令正常执行时,有的还回有命令返回值:

根据命令及其功能不同,结果各不相同;


引用命令的执行结果:

$(COMMAND)

或`COMMAND`


六、引用

强引用:''

弱引用:""

命令引用:``

七、快捷键

Ctrl+a:跳转至命令行行首

Ctrl+e:跳转至命令行行尾


Ctrl+u:删除行首至光标所在处之间的所有字符;

Ctrl+k:删除光标所在处至行尾的所有字符;


Ctrl+l:清屏,相当于clear

八、globbing:文件名通配(整体文件名匹配,而非部分)


匹配模式:元字符

*:匹配任意长度的任意字符

pa*, *pa*, *pa, *p*a*

pa, paa, passwd

?:匹配任意单个字符

pa?, ??pa, p?a, p?a?

pa, paa, passwd

[]:匹配指定范围内的任意单个字符

有几种特殊格式:

[a-z], [A-Z], [0-9], [a-z0-9]

[[:upper:]]:所有大写字母

[[:lower:]]:所有小写字母

[[:alpha:]]:所有字母

[[:digit:]]:所有数字

[[:alnum:]]:所有的字母和数字

[[:space:]]:所有空白字符

[[:punct:]]:所有标点符号


pa[0-9][0-9], 2[0-9][0-9]

[^]:匹配指定范围外的任意单个字符

[^[:upper:]]

[^0-9]

[^[:alnum:]]

九、IO重定向及管道


程序:指令+数据

程序:IO


可用于输入的设备:文件

键盘设备、文件系统上的常规文件、网卡等;

可用于输出的设备:文件

显示器、文件系统上的常规文件、网卡等;


程序的数据流有三种:

输入的数据流;<-- 标准输入(stdin),键盘;

输出的数据流:--> 标准输出(stdout),显示器;

错误输出流:  --> 错误输出(stderr),显示器;


fd: file descriptor,文件描述符

标准输入:0

标准输出:1

错误输出:2


IO重定向:


输出重定向:>

特性:覆盖输出

输出重定向:>>

特性:追加输出


# set -C

禁止覆盖输出重定向至已存在的文件;

此时可使用强制覆盖输出:>|

# set +C

关闭上述特性


错误输出流重定向:2>, 2>>


合并正常输出流和错误输出流:

(1) &>, &>>

(2) COMMAND > /path/to/somefile 2>&1

    COMMAND >> /path/to/somefile 2>&1


特殊设备:/dev/null


输入重定向:<


tr命令:

tr [OPTION]... SET1 [SET2]

把输入的数据当中的字符,凡是在SET1定义范围内出现的,通通对位转换为SET2出现的字符


用法1:

tr SET1 SET2 < /PATH/FROM/SOMEFILE

用法2:

tr -d SET1 < /PATH/FROM/SOMEFILE


注意:不修改原文件


Here Document:<<


cat << EOF

cat > /PATH/TO/SOMEFILE << EOF


管道:连接程序,实现将前一个命令的输出直接定向后一个程序当作输入数据流

COMMAND1 | COMMAND2 | COMMAND3 | ...


tee命令:

COMMAND | tee /PATH/TO/SOMEFILE



bash特性及bash脚本编程初步


终端,附着在终端的接口程序:

GUI:KDE, GNome, Xfce

CLI:/etc/shells

bash

zsh

fish


bash的特性:

命令行展开:~, {}

命令别名:alias, unalias

命令历史:history

文件名通配:glob

快捷键:Ctrl+a, e, u, k, l

命令补全:$PATH

路径补全:


bash特性之:命令hash

缓存此前命令的查找结果:key-value

key:搜索键

value:值


hash命令:

hash:列出

hash -d COMMAND:删除

hash -r:清空


bash的特性之:变量

程序:指令+数据

指令:由程序文件提供;

数据:IO设备、文件、管道、变量


程序:算法+数据结构


变量名+指向的内存空间


变量赋值:name=value

变量类型:存储格式、表示数据范围、参与的运算

编程语言:

强类型变量

弱类型变量:

bash把所有变量统统视作字符型;

bash中的变量无需事先声明;相当于,把声明和赋值过程同时实现;

声明:类型,变量名

变量替换:把变量名出现的位置替换为其所指向的内存空间中数据;

变量引用:${var_name}, $var_name

变量名:变量名只能包含数字、字母和下划线,而且不能以数字开头;

变量名:见名知义,命名机制遵循某种法则;不能够使用程序的保留字,例如if, else, then, while等等;

bash变量类型:

本地变量:作用域仅为当前shell进程;

环境变量:作用域为当前shell进程及其子进程;

局部变量:作用域仅为某代码片断(函数上下文);


位置参数变量:当执行脚本的shell进程传递的参数;

特殊变量:shell内置的有特殊功用的变量;

$?:

0:成功

1-255:失败


本地变量:

变量赋值:name=value

变量引用:${name}, $name

"":变量名会替换为其值;

'':变量名不会替换为其值;

查看变量:set

撤销变量:unset name

注意:此处非变量引用;


环境变量:

变量赋值:

(1) export name=value

(2) name=value

    export name

(3) declare -x name=value

(4) name=value

declare -x name

变量引用:${name}, $name


注意:bash内嵌了许多环境变量(通常为全大写字符),用于定义bash的工作环境

PATH, HISTFILE, HISTSIZE, HISTFILESIZE, HISTCONTROL, SHELL, HOME, UID, PWD, OLDPWD


查看环境变量:export, declare -x, printenv, env

撤销环境变量:unset name


只读变量:

(1) declare -r name

(2) readonly name


只读变量无法重新赋值,并且不支持撤销;存活时间为当前shell进程的生命周期,随shell进程终止而终止;


bash特性之多命令执行:

~]# COMMAND1; COMMAND2; COMMAND3; ...


逻辑运算:

运算数:真(true, yes, on, 1)

    假(false, no, off, 0)


与:

1 && 1 = 1

1 && 0 = 0

0 && 1 = 0

0 && 0 = 0

或:

1 || 1 = 1

1 || 0 = 1

0 || 1 = 1

0 || 0 = 0

非:

! 1 = 0

! 0 = 1


短路法则:

~]# COMMAND1 && COMMAND2

COMMAND1为“假”,则COMMAND2不会再执行;

否则,COMMAND1为“真”,则COMMAND2必须执行;


~]# COMMAND1 || COMMAND2

COMMAND1为“真”,则COMMAND2不会再执行;

否则,COMMAND1为“假”,则COMMAND2必须执行;


示例:~]# id $username || useradd $username


shell脚本编程:

编程语言的分类:根据运行方式

编译运行:源代码 --> 编译器 (编译)--> 程序文件;

解释运行:源代码 --> 运行时启动解释器,由解释器边解释边运行;

根据其编程过程中功能的实现是调用库还是调用外部的程序文件:

shell脚本编程:

利用系统上的命令及编程组件进行编程;

完整编程:

利用库或编程组件进行编程;

编程模型:过程式编程语言,面向对象的编程语言

程序=指令+数据

过程式:以指令为中心来组织代码,数据是服务于代码;

顺序执行

选择执行

循环执行

代表:C,bash

对象式:以数据为中心来组织代码,围绕数据来组织指令;

类(class):实例化对象,method;

代表:Java, C++, Python

shell脚本编程:过程式编程,解释运行,依赖于外部程序文件运行;

如何写shell脚本:

脚本文件的第一行,顶格:给出shebang,解释器路径,用于指明解释执行当前脚本的解释器程序文件

常见的解释器:

#!/bin/bash

#!/usr/bin/python

#!/usr/bin/perl

文本编程器:nano

行编辑器:sed

全屏幕编程器:nano, vi, vim

shell脚本是什么?

命令的堆积;

但很多命令不具有幂等性,需要用程序逻辑来判断运行条件是否满足,以避免其运行中发生错误;

运行脚本:

(1) 赋予执行权限,并直接运行此程序文件;

chmod +x /PATH/TO/SCRIPT_FILE

/PATH/TO/SCRIPT_FILE

(2) 直接运行解释器,将脚本以命令行参数传递给解释器程序;

bash /PATH/TO/SCRIPT_FILE

注意:脚本中的空白行会被解释器忽略;

            脚本中,除了shebang,余下所有以#开头的行,都会被视作注释行而被忽略;此即为注释行;

    shell脚本的运行是通过运行一个子shell进程实现的;

练习1:写一个脚本,实现如下功能;

(1) 显示/etc目录下所有以大写p或小写p开头的文件或目录本身;

(2) 显示/var目录下的所有文件或目录本身,并将显示结果中的小写字母转换为大写后显示;

(3) 创建临时文件/tmp/myfile.XXXX;

bash的配置文件:

两类:

profile类:为交互式登录的shell进程提供配置

bashrc类:为非交互式登录的shell进程提供配置

登录类型:

交互式登录shell进程:

直接通过某终端输入账号和密码后登录打开的shell进程;

使用su命令:su - USERNAME, 或者使用 su -l USERNAME执行的登录切换;

非交互式登录shell进程:

su USERNAME执行的登录切换;

图形界面下打开的终端;

运行脚本

profile类:

全局:对所有用户都生效;

/etc/profile 

/etc/profile.d/*.sh

用户个人:仅对当前用户有效;

~/.bash_profile

功用:

1、用于定义环境变量;

2、运行命令或脚本;

bashrc类:

全局:

/etc/bashrc 

用户个人:

~/.bashrc

功用:

1、定义本地变量;

2、定义命令别名;

注意:仅管理员可修改全局配置文件;

交互式登录shell进程:

/etc/profile --> /etc/profile.d/* --> ~/.bash_profile --> ~/.bashrc --> /etc/bashrc

非交互式登录shell进程:

~/.bashrc --> /etc/bashrc --> /etc/profile.d/*

命令行中定义的特性,例如变量和别名作用域为当前shell进程的生命周期;

配置文件定义的特性,只对随后新启动的shell进程有效;

让通过配置文件定义的特性立即生效:

(1) 通过命令行重复定义一次;

(2) 让shell进程重读配置文件;

~]# source /PATH/FROM/CONF_FILE

~]# .  /PATH/FROM/CONF_FILE

问题1:定义对所有用户都生效的命令别名,例如 lftps='lftp 172.16.0.1/pub'?

问题2:让centos用户登录时,提供其已经登录,并显示当前系统时间?

回顾:

bash的特性:hash, 变量

命令hash:hash命令

变量:

本地变量、环境变量、局部变量

位置参数变量、特殊变量

变量赋值:name=value, export name=value, declare -x name=value

变量引用:$name, ${name}

撤销:unset name

bash脚本编程,运行脚本

#!/bin/bash

bash的配置文件

profile类:登录式shell

bashrc类:非登录式shell

登录式shell: /etc/profile --> /etc/profile.d/*.sh --> ~/.bash_profile --> ~/.bashrc --> /etc/bashrc

非登录式shell:~/.bashrc --> /etc/bashrc --> /etc/profile.d/*.sh


练习:定义一个对所有用户都生效的命令别名,例如:lftps='lftp 172.168.0.1/pub'

                    alias.png

二、编写脚本,实现自动添加三个用户,并计算这三个用户的uid之和。

                        三周useradd.png