此文是对于centos系统中bash特性的较为详尽的介绍。
bash基础特性1:命令历史
命令历史:
shell进程会在其会话中保存此前用户提交、执行过的命令,称之为“命令历史”;
那么,如何来查看命令历史呢?
history : 查看历史命令(内存中的所有历史命令)
用法:
history [-c] [-d offest] [n]
history -anrw [文件名]
history -ps 参数 [参数....]
定制·history·的功能可通过环境变量来实现,有以下两种:
HISTSIZE :
shell进程可保留的历史命令的条数
HISTFILE :
持久保存命令历史的文件,文件名为 .bash_history 。在当前shell中输入的命令历史,直接保存在内存中,当shell退出时将此shell中的命令历史保存到文件.bash_history中。
HISTFILESIZE :
HISTFILE文件的大小,当命令历史条数大于这个值,将会把旧命令踢出、新的历史命令写入HISTFILE;
示例:
[root@localhost jeffrey]# history
1 ls
2 sudo apt install yum
3 yum install tree
4 tree
5 yum install tree
6 tree
7 ls
.......
104 who -r
105 w
106 histtory
107 history
选项:
-c : 清空命令历史
-d offest : 删除指定位置的命令历史
-d offest n : 删除从指定位置开始的n条命令
-w : 将内存中的命令历史保存到文件(HISTFILE)中
-r : 将文件(HISTFILE)中的命令历史读取到内存中
history # : 显示最近的#条命令
示例:
[root@localhost jeffrey]# history -c
[root@localhost jeffrey]# history
1 history
[root@localhost jeffrey]# history -r
[root@localhost jeffrey]# history
1 history
2 cat HISTFILE
3 history -r
4 ls
5 sudo apt install yum
6 yum install tree
7 tree
.......
98 which mv
99 which --skip-alias rm
100 which --skip-alias mv
101 reboot
102 history
[root@localhost jeffrey]# cat .bash_history
ls
cd Document
ls
cd Documents
ls
tree
sudo install tree
sudo apt install yum
su
type
type ls
[root@localhost jeffrey]# history -w .bash_history
[root@localhost jeffrey]# cat .bash_history
history
cat HISTFILE
history -r
ls
sudo apt install yum
yum install tree
tree
.......
cat .bash_history
echo $HISTSIZE
echo $HISTFILESIZE
cat .bash_history
history -w
cat .bash_history
history
cat .bash_history
history -w .bash_history
那么,该如何调用命令历史列表中的历史呢?
! n : 执行历史列表中的第n条命令
! ! : 指向上一条命令;更简单的是“向上方向键”
!STRING : 执行命令历史列表中最近一次以字符串’ STRING ‘开头的命令
示例:由于·ls·命令是我们上一条执行的命令,所以·!l·匹配到的最近的以l开头的命令就是ls.
[root@localhost jeffrey]# ls
Desktop Documents Downloads Music Pictures Public
Templates Videos
[root@localhost jeffrey]# man useradd
[root@localhost jeffrey]# !l
ls
Desktop Documents Downloads Music Pictures Public
Templates Videos
注:命令的重复执行有时候需要依赖于幂等性;
那么,到底什么是幂等性呢?
示例:
[root@localhost jeffrey]# mkdir mybook
[root@localhost jeffrey]# !m
mkdir mybook
由于,我们执行’ mkdir mybook ‘后,目录’ mybook ’ 已经创建了,所以,再一次执行该命令就会提示错误;所以,该命令的重复执行不具有幂等性!
下面,介绍一下如何调用上一条命令的最后一个参数。
Esc , . : 先按下Esc,然后松开,再按下 . 即可
!$ : 同时按住 !和 $
如何控制命令历史记录的方式呢?
答案是:通过环境变量“HISTCONTROL”
HISTCONTORL=ignoredups : 忽略重复(相同且连续)的命令
HISTCONTORL=ignorespace : 忽略以空白字符开头的命令
HISTCONTORL=ignoreboth : 以上两者同时生效
示例:
[root@localhost mybook]# HISTCONTORL=ignoredups
[root@localhost mybook]# HISTCONTORL=ignorespace
[root@localhost mybook]# HISTCONTORL=ignoreboth
可用以下方式来修改变量的值:
NAME='VALUE'
bash基础特性2:命令补全和路径补全
命令查找:
shell程序在接收到用户执行命令的请求,分析完成之后,最左侧的字符串会被当做命令;然后执行命令查找机制:
(1)在shell内部命令中查找与命令名相同的文件,并执行、发起 一个进程
(2)若未找到,则根据PATH环境变量中设定的目录,自左而右逐个搜索目录下的文件名,然后发起一个进程;命令补全:
首先,在命令行给出一个待补全字符串,按下Tab键:
(1)若待补全字符串能唯一标识某个命令程序文件,则会直接补全;
(2)若不能唯一标识,此时,再按一次Tab键则会显示所有可能命令的列表
示例:输入’ mkdi ‘进行匹配,按一下Tab键无法补全,所以,再按一次Tab键,便出现所有可能命令的列表
[root@localhost mybook]# mkdi
mkdict mkdir
路径补全:
在给定的起始路径下,以对应路径下的打头字符串来逐一匹配起始路径下的每个文件。
若能唯一标识,则直接补全路径;
否则,再敲一次Tab,会给出所有可能的列表;
示例:
[root@localhost jeffrey]# cd D
Desktop/ Documents/ Downloads/
bash基础特性3:命令行展开
~ : 自动展开为用户的家目录,或指定的家目录
{} : 可承载一个以逗号分隔的路径列表,并能将其展开为多个路径;
示例:
~ : 自动展开为用户的家目录 或 指定用户的家目录;
[root@localhost jeffrey]# echo ~
/root
{ } : 可承载一个以逗号分隔的路径列表,并能将其展开为多个路径 ;
[root@localhost jeffrey]# mkdir -pv /work/hardwares/x/{y1,y2}
mkdir: created directory ‘/work’
mkdir: created directory ‘/work/hardwares’
mkdir: created directory ‘/work/hardwares/x’
mkdir: created directory ‘/work/hardwares/x/y1’
mkdir: created directory ‘/work/hardwares/x/y2’
[root@localhost jeffrey]# tree /work
/work
`-- hardwares
`-- x
|-- y1
`-- y2
4 directories, 0 files
这里我们查看命令行展开,使用了tree命令
tree : 显示完整目录树
用法:
tree [options] [directory]
选项:
-L level : 指定要要显示的层级
以下做几个练习题:
(1) 创建/mybook目录下的:a_c, a_d, b_c, b_d
[root@localhost /]# mkdir -pv /mybook/{a,b}_{c,d}
mkdir: created directory ‘/mybook/a_c’
mkdir: created directory ‘/mybook/a_d’
mkdir: created directory ‘/mybook/b_c’
mkdir: created directory ‘/mybook/b_d’
[root@localhost /]# tree mybook
mybook
|-- a_c
|-- a_d
|-- b_c
`-- b_d
4 directories, 0 files
(2) 创建/tmp/mylinux目录下的:
mylinux/
├── bin
├── boot
│ └── grub
├── dev
├── etc
│ ├── rc.d
│ │ └── init.d
│ └── sysconfig
│ └── network-scripts
├── lib
│ └── modules
├── lib64
├── proc
├── sbin
├── sys
├── tmp
├── usr
│ └── local
│ ├── bin
│ └── sbin
└── var
├── lock
├── log
└── run
[root@localhost /]# mkdir -pv /work/mylinux/{bin,boot/grub,dev,
etc/{rc.d/init.d,sysconfig/network_scripts},lib/modules,lib64,proc,
sbin,sys,tmp,usr/local/{bin,sbin},var/{lock,log,run}}
mkdir: created directory ‘/work/mylinux’
mkdir: created directory ‘/work/mylinux/bin’
mkdir: created directory ‘/work/mylinux/boot’
mkdir: created directory ‘/work/mylinux/boot/grub’
mkdir: created directory ‘/work/mylinux/dev’
mkdir: created directory ‘/work/mylinux/etc’
mkdir: created directory ‘/work/mylinux/etc/rc.d’
mkdir: created directory ‘/work/mylinux/etc/rc.d/init.d’
mkdir: created directory ‘/work/mylinux/etc/sysconfig’
mkdir: created directory ‘/work/mylinux/etc/sysconfig/network_scripts’
mkdir: created directory ‘/work/mylinux/lib’
mkdir: created directory ‘/work/mylinux/lib/modules’
mkdir: created directory ‘/work/mylinux/lib64’
mkdir: created directory ‘/work/mylinux/proc’
mkdir: created directory ‘/work/mylinux/sbin’
mkdir: created directory ‘/work/mylinux/sys’
mkdir: created directory ‘/work/mylinux/tmp’
mkdir: created directory ‘/work/mylinux/usr’
mkdir: created directory ‘/work/mylinux/usr/local’
mkdir: created directory ‘/work/mylinux/usr/local/bin’
mkdir: created directory ‘/work/mylinux/usr/local/sbin’
mkdir: created directory ‘/work/mylinux/var’
mkdir: created directory ‘/work/mylinux/var/lock’
mkdir: created directory ‘/work/mylinux/var/log’
mkdir: created directory ‘/work/mylinux/var/run’
[root@localhost /]# tree /work
/work
|-- hardwares
| `-- x
| |-- y1
| `-- y2
`-- mylinux
|-- bin
|-- boot
| `-- grub
|-- dev
|-- etc
| |-- rc.d
| | `-- init.d
| `-- sysconfig
| `-- network_scripts
|-- lib
| `-- modules
|-- lib64
|-- proc
|-- sbin
|-- sys
|-- tmp
|-- usr
| `-- local
| |-- bin
| `-- sbin
`-- var
|-- lock
|-- log
`-- run
29 directories, 0 files
bash基础特性4:命令的执行状态结果
(1)bash通过状态返回值反映命令执行结果;此结果保存在bash中的特殊变量 $? 中。
若命令执行成功,返回值为0;若失败,返回值为1-255;
示例:
[root@hac-cent-jef jeffrey]# pwd
/home/jeffrey
[root@hac-cent-jef jeffrey]# echo $?
0
[root@hac-cent-jef jeffrey]# lss
bash: lss: command not found...
Similar command is: 'ls'
[root@hac-cent-jef jeffrey]# echo $?
127
2)若要引用命令的执行结果:$(COMMAND)或 `COMMAND`(反引号)
例:以hello为名称,创建一个文件夹
[root@hac-cent-jef jeffrey]# mkdir $(echo 'hello')
[root@hac-cent-jef jeffrey]# ls
Documents hello Music var Videos Work yang_2.c yang.c
bash基础特性5:引用
单引号 ‘ ’ : 表示强引用
双引号 ” ” : 表示弱引用
反引号: 表示命令引用
bash基础特性6:快捷键
Ctrl+a : 跳转到命令行首
Ctrl+e : 跳转到命令行尾
Ctrl+u : 删除命令行首到光标之间的字符
Ctrl+k : 删除光标到行尾之间的字符
Ctrl+l : 清屏,相当于clear
bash基础特性7:globbing 文件名通配
匹配模式:元字符
元字符主要包括:
* : 匹配任意长度的任意字符
? : 匹配任意单个字符
[ ] : 匹配指定范围内的单个字符
[^] : 匹配指定范围外的单个字符
其中,元字符 [ ] 和 [^] 的使用有几种特别形式 :
[a-z] : 匹配一个大写或小写字母,等价于[A-Z]
[0-9] : 匹配一个数字
[a-z0-9] : 匹配一个字母或数字
[abcxyz] : 匹配字符串abcxyz中的一个字母
2[0-9][0-9] :匹配200-299之间的数字
[[:upper:]] : 匹配一个大写字母
[[:lower:]] : 匹配一个小写字母
[[:alpha:]] : 匹配某个大写或小写字母
[[:digit:]] : 匹配一个数字
[[:alnum:]] : 匹配一个字母或数字,等价于:[[:alpha:][:digit:]]
[[:space:]] : 匹配一个空白字符
[[:punct:]] : 匹配一个标点符号
[^0-9] : 匹配一个非数字字符
[^[:upper:]] : 匹配一个非大写字母的字符
熟悉了上面的元字符,下面我们趁热打铁,来做几道练习题吧!
1,显示/var目录下所有以1开头、以一个小写字母结尾、且中间出现一位任意字符的文件或目录
[root@hac-cent-jef ~]# ls -d /var/1*[[:lower:]]
/var/1love
2,显示/etc目录下,以任一个数字开头,且以非数字结尾的文件或目录
[root@hac-cent-jef ~]# ls -d /etc/[0-9]*[^0-9]
/etc/1kshdlv /etc/34jkbvrl /etc/4t5d
3,显示/etc目录下,以非字母开头,后面跟一个字母及其他任意长度字符的文件或目录
[root@hac-cent-jef ~]# ls -d /etc/[^a-z][a-z]*
/etc/1kshdlv /etc/4t5d
4,复制/etc目录下,所有以m开头的、以非数字结尾的文件或目录至/tmp/mybook中
[root@hac-cent-jef ~]# cp -r /etc/m*[^0-9] /tmp/mybook
[root@hac-cent-jef ~]# ls /tmp/mybook
machine-id mail.rc maven modprobe.d mtab my.cnf
magic makedumpfile.conf.sample mime.types modules-load.d mtools.conf my.cnf.d
mailcap man_db.conf mke2fs.conf motd multipath
5,复制/usr/share/man目录下,所有以man开头、后跟一个数字结尾的文件或目录至/tmp/man目录下
[root@hac-cent-jef ~]# cp -r /usr/share/man/man*[0-9] /tmp/man
[root@hac-cent-jef ~]# ls /tmp/man
man1 man2 man3 man4 man5 man6 man7 man8 man9
6,复制/etc目录下,所有以.conf结尾,且以m,n,r,p开头的文件或目录至/tmp/conf.d
[root@hac-cent-jef ~]# cp -r /etc/[mnrp]*.conf /tmp/conf.d
[root@hac-cent-jef ~]# ls /tmp/conf.d
man_db.conf mtools.conf nfsmount.conf ntp.conf pnm2ppa.conf resolv.conf rsyslog.conf
mke2fs.conf nfs.conf nsswitch.conf pbm2ppa.conf request-key.conf rsyncd.conf
bash基础特性8:I/O重定向及管道
程序=指令+数据
可用于输入的设备、文件有:键盘、文件系统的常规文件、网卡等
可用于输出的设备、文件有:显示器、文件系统的常规文件、网卡等
程序的数据流有三种:
输入的数据流 <————标准输入(stdin) 键盘
输出的数据流 ————>标准输出(stdout) 显示器
错误输出流 ————>错误输出(stderr)显示器
每一种数据流都有其文件描述符fd(即file descriptor):
标准输入 : 0
标准输出 : 1
错误输出 : 2
下面重点介绍:I/O重定向
输出重定向 : >
特点:覆盖输出
输出重写向: >>
特点:追加输出
set -c
禁止输出重定向覆盖已存在的文件
set +c
取消上述禁止的功能
强制覆盖 : >|
错误输出流重定向 : 2>
特点:覆盖输出
错误输出流重写向 : 2>>
特点:追加输出
那么,如果想让正常输出流和错误输出流重定向到同一个文件当中呢?
可以合并正常输出流和错误输出流:
- 重定向: &>
- 重写向 : &>>
或者使用以下方式:
- COMMAND > /path/to/somefile 2>&1
- COMMAND >> /path/to/somefile 2>&1
示例:
(1),输出重定向
[root@hac-cent-jef ~]# ls
811.c 812.c anaconda-ks.cfg initial-setup-ks.cfg
[root@hac-cent-jef ~]# ls > document
[root@hac-cent-jef ~]# cat document
811.c
812.c
anaconda-ks.cfg
document
initial-setup-ks.cfg
(2)输出重写向
[root@hac-cent-jef ~]# echo 'hello world'
hello world
[root@hac-cent-jef ~]# echo 'hello world' >> document
[root@hac-cent-jef ~]# cat document
811.c
812.c
anaconda-ks.cfg
document
initial-setup-ks.cfg
hello world
对于I/O重定向,还有一个非常特殊的设备:/dev/null,我们称之为“数据黑洞”。这是因为所有输入到/dev/null中的数据都会被吞噬!
示例:将ls命令的结果输出重定向到数据黑洞/dev/null中
[root@hac-cent-jef ~]# ls
811.c 812.c anaconda-ks.cfg document initial-setup-ks.cfg name
[root@hac-cent-jef ~]# ls &> /dev/null
[root@hac-cent-jef ~]# lss &> /dev/null
[root@hac-cent-jef ~]# cat /dev/null
[root@hac-cent-jef ~]#
讲完了输出,我们来研究一下输入吧~
在此之前,我们先来认识tr命令吧!
tr : 进行字符的替换
用法:
tr [optiom]… SET1 [SET2]
将SET1中的字符替换为SET2中对位的字符
注意:tr命令只是改变了文件内容输出在屏幕上的结果,而并不改变该文件的内容;
接着来说输入重定向:
- 输入重定向 : <
与tr命令结合来举例:
(1)将文件document中的所有小写字母换成大写字母输出
[root@hac-cent-jef ~]# tr [a-z] [A-Z] < document
811.C
812.C
ANACONDA-KS.CFG
DOCUMENT
INITIAL-SETUP-KS.CFG
HELLO WORLD
(1)将文件document中的所有数字换成字母输出
[root@hac-cent-jef ~]# tr [0-9] [a-z] < document
ibb.c
ibc.c
anaconda-ks.cfg
document
initial-setup-ks.cfg
hello world
还有一个重要的知识点:
Here document <<
用法:
cat << EOF : 从键盘输入数据并以EOF为结束符
cat > FILE << EOF :将从键盘输入的数据保存到文件中,并以EOF为结束符
示例:
[root@hac-cent-jef ~]# cat << EOF
> Hello
> world
> !
> EOF
Hello
world
!
[root@hac-cent-jef ~]# cat > name << EOF
> JOHN
> LILY
> CHERRY
> JEFFREY
> EOF
[root@hac-cent-jef ~]# cat name
JOHN
LILY
CHERRY
JEFFREY
最后介绍inux中的非常重要的工具:管道
什么是管道:
连接程序,实现将一个命令的输出直接定向后一个程序输入
用法:
COMMAND1 | COMMAND2 | COMMAND3
示例1:将命令执行结果中的小写字母全部替换为大写字母
[root@hac-cent-jef ~]# cat /etc/issue
\S
Kernel \r on an \m
[root@hac-cent-jef ~]# cat /etc/issue | tr 'a-z' 'A-Z'
\S
KERNEL \R ON AN \M
示例2:只显示who命令输出结果的第一行,然后把第一行中的小写字母换成大写字母,最后删除所有输出结果中包含的所有数字
[root@hac-cent-jef ~]# who
jeffrey pts/1 2018-08-30 23:28 (:0)
jeffrey :0 2018-08-30 14:36 (:0)
[root@hac-cent-jef ~]# who | head -1
jeffrey pts/1 2018-08-30 23:28 (:0)
[root@hac-cent-jef ~]# who | head -1 | tr 'a-z' 'A-Z'
JEFFREY PTS/1 2018-08-30 23:28 (:0)
[root@hac-cent-jef ~]# who | head -1 | tr 'a-z' 'A-Z' | tr -d '0-9'
JEFFREY PTS/ -- : (:)
此时此刻,让我们再来学习一个新的命令吧!
tee : 将输入数据流显示到屏幕上,同时保存到文件中
用法:
COMMAND | tee /PATH/TO/SOMEFILE
示例:把cat命令的结果输出到屏幕上,同时保存到文件/tmp/issue.tee中
[root@hac-cent-jef ~]# cat /etc/issue | tee /tmp/issue.tee
\S
Kernel \r on an \m
[root@hac-cent-jef ~]# cat /tmp/issue.tee
\S
Kernel \r on an \m
我们不如来做个练习吧!
练习1:把/etc/passwd文件中的前6行的信息转换为大写字符后输出
[root@hac-cent-jef ~]# cat /etc/passwd | head -6 | tr 'a-z' 'A-Z'
ROOT:X:0:0:ROOT:/ROOT:/BIN/BASH
BIN:X:1:1:BIN:/BIN:/SBIN/NOLOGIN
DAEMON:X:2:2:DAEMON:/SBIN:/SBIN/NOLOGIN
ADM:X:3:4:ADM:/VAR/ADM:/SBIN/NOLOGIN
LP:X:4:7:LP:/VAR/SPOOL/LPD:/SBIN/NOLOGIN
SYNC:X:5:0:SYNC:/SBIN:/BIN/SYNC
好啦!以上就是本此分享的所有内容了,若有错误,欢迎批评指正!
白白!