一、Shell
通常我们操作系统有图形界面(GUI)和命令界面(CLI)。
Linux 中常用 GUI 有:Gnome,KDE,Xface(xwindow协议)。
Linux 中常用 CLI 有:bsh,csh,ksh(商业化也有社区版),bash(兼bsh;csh;ksh的功能;也是Linux默认shell),zsh(最新的功能非常强大)。
查看 Linux 支持的 Shell。
1 |
$ cat /etc/shell |
Shell 称为命令解释器,通常是用户与操作系统交互的界面。在 Redhat 系列发行版系统中,bash 就是实现 shell 的其中一种程序。Bash 自身是一个外部程序但是当它启动之后就会有一些内部命令,bash 也是一个进程。每一个用户或是一个用户登录多次就会开启多个 bash 也是多个进程但是每一个进程之间的 PID 号不同,在每个进程看来;当前主机上只有内核和当前进程,进程同时是程序的副本是程序执行的实例。每个用户登录的 shell 的工作环境都可以是不同的做装饰,在一个 bash 中可以打开子 shell 如 csh,ksh 或是 bash 等。
二、Bash特性(man bash)
1. 支持命令历史
Bash会自动记录过去曾经执行过的命令,并保存在一段内存的缓冲区中,当用户正常退出系统之后,内存缓冲区中的那些命令就会追加到用户家目录隐藏文件.bash_history中。默认保存1000条,其对应的环境变量为“echo $HISTSIZE”。
支持的命令如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# 查看命令历史 $ history # 清除所有命令历史 $ history -c # 清除第100条历史记录 $ history -d 100 # 清除第100后的10条命令历史 $ history -d 100 10 # 保存命令历史至历史文件.bash_history $ history -w # 执行历史命令的第100条 $ !100 # 执行上一条命令 $ !! # 执行命令历史中最近一个以指定字符串开头的命令 $ !string |
另外很多发行版的默认的history是没有用户和操作时间的,这个对于需要查看原来的操作内容的时候就提供了麻烦,man 了下history,发现有个变量是可以设定history这个显示格式的,这个变量就是HISTTIMEFORMAT,使用方法如下:
1 |
$ export HISTTIMEFORMAT="`whoami` : | %F | %T: | " |
然后就可以看到带有用户和时间的history了,把这个保存到当前用户的.bash_profile里面,就可以开机自动加载了。
1 2 3 4 5 6 7 8 9 10 |
$ history | head 1 root : | 2015-04-20 | 22:00:58: | clear 2 root : | 2015-04-20 | 22:00:58: | tac END > /etc/1.txt 3 root : | 2015-04-20 | 22:00:58: | install /etc/1.txt 4 root : | 2015-04-20 | 22:00:58: | touch /etc/1.txt 5 root : | 2015-04-20 | 22:00:58: | tac END > /etc/1.txt 6 root : | 2015-04-20 | 22:00:58: | rm -fr /etc/1.txt 7 root : | 2015-04-20 | 22:00:58: | clear 8 root : | 2015-04-20 | 22:00:58: | ls 9 root : | 2015-04-20 | 22:00:58: | init 3 |
另外使用history还有一个非常实用的功能,就是CTRL+R组合键,会出现如下提示符:
1 |
(reverse-i-search)`': |
在提示符内输入相应的任意字符,可以进行历史命令搜索匹配显示,然后直接回车,就会执行匹配到的命令。
1 |
(reverse-i-search)`ls': ls /etc/php/7.0/fpm/pool.d/ |
2. 支持命令补全
命令补全:搜索PATH环境变量所指定的每个路径下以我们给出的字符串开头的可执行文件,如果多于一个,两次tab,可以给出列表,否则将直接补全。
路径补全:搜索我们给出的起始路径下的每个文件名并试图补全。
3. 支持管道符“|”
“|”管道是Linux系统提供的多任务协调机制的一种,应用十分广泛。管道可分为匿名和命名两种,但是不管怎样它们都拥有一个共同的特性,就是数据只能从管道的一端写入并从另一端读取,而且读出的顺序与写入的顺序是相同的。所以管道也叫做FIFO(first input first output)。
如命令:
1 |
$ echo "redhat" | passwd --stdin root |
这条命令就是通过echo输出字符串redhat,然后通过管道送给root当密码使用;其中–stdin表示标准输入。还有stdout表示标准输出,stderr表示错误输出。
4. 支持I/O重定向
I/O重定向也是Linux中提供的一种多任务协调机制,所谓I/O重定向,就是把输出给A的东西重定向给B,或者反过来说将要从A处获得的输入重定向到B处去获得了。
常用定向符如下:
1 2 3 4 5 6 7 8 9 |
> #标准输出重定向覆盖文件原有内容; >> #标准内容追加echo "" >> /tmp/1.txt; >| #强制输出重定向覆盖文件原有内容; 2> #错误输出重定向覆盖原有文件内容; 2>> #错误内容追加; &> #正确或是错误内容都定向到文件中并覆盖; &>> #正确或是错误内容都追加到文件中; < #输入重定向; << #<span style="font-family: 宋体;">输入追加重定向,</span>如: |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
$ cat << END 或 $ cat >> /tmp/1.txt >> END # 开启不允许重定向覆盖原有文件内容 $ set -c # 关闭不允许重定向覆盖原有文件内容 $ set +c # 利用管道和tee命令实现对标准输出信息保存到文件同时并显示到屏幕上 $ echo "Hello world!" | tee /tmp/1.txt # 以追加的方式保存到文件 $ tee -a /tmp/1.txt |
5. 支持命令别名
在shell中定义的别名仅在当前shell生命周期中有效;别名的有效范围仅为当前shell进程
支持的别名命令如下:
1 2 3 4 |
alias #查看系统所有别名; alias CMDALIAS="CMD" #定义别名只在当前用户有效; unalias CMDALIAS #撤销命令别名; \CMD #强行使用命令本身; |
6. 命令替换“$()”
命令替换在shell中就是把此命令中某个子命令的执行结果作为此命令的执行对象,如:
1 2 3 4 |
$ echo "The current directory is $(pwd)" The current directory is /root $ touch ./file-$(date +%F-%H-%M-%S).txt file-2015-08-25-14-11-05.txt |
7. 支持命令行编辑
1 2 3 4 5 6 |
Ctrl+a #跳到命令行首; Ctrl+e #跳到命令行尾; Ctrl+u #删除光标至命令行首的内容; Ctrl+k #删除光标至命令行尾的内容; Ctrl+l #清屏支持命令行展开; Ctrl+s #终止当前进程; |
8. 支持文件名通配
*:匹配任意长度的任意字符
1 2 3 4 5 6 7 8 |
# 表示以i开头的显示; $ ls i* # 表示以i开头以g结尾的显示; $ ls i*g # 表示有y的都显示; $ ls *i* |
?:配置任意单个字符
1 2 3 4 5 |
# 表示y前面必须要有一个字符y后面随意的显示; $ ls ?y* # 表示y前面必须要有三个字符y后面随意的显示; $ ls ???y* |
[]:配指定范围内的指定字符,大概有以下这些(man 7 glob可以查看帮助)
1 2 3 4 5 6 7 8 9 10 11 12 13 |
[abc] [a-z] [A-Z] [0-9] [a-zA-Z] [0-9a-zA-Z] [[:space:]] #空白字符; [[:punct:]] #标点符号; [[:lower:]] #小写字母; [[:upper:]] #大写字母; [[:alpha:]] #大小写字母; [[:digit:]] #数字; [[:alnum:]] #数字和大小写字母; |
案例:
1 2 3 4 5 6 7 8 |
# 以字母开头数字结尾的显示 $ ls [a-zA-Z]*[0-9] # 以字母开头数字结尾的显示 $ ls [[:alpha:]]*[[:digit:]] # 显示文件名中有空白字符的文件(创建空白字符文件touch 'a b') $ ls *[[:space:]]* |
[^]:匹配指定范围外的所有字符
1 2 3 4 5 |
# 不是以数字开头的都显示 $ ls [^0-9]* # 以字母开头非数字结尾的显示 $ ls [[:alpha:]]*[^[:digit:]] |
9. 管理员和普通用户登录格式
1 2 |
[root@localhost ~]# 管理员(#) [root@localhost ~]$ 普通用户($) |
10. 支持变量(变量是什么后面有讲)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# 自定义变量赋值; $ VERSION="edition" # 使用echo输出变量,{}可省略; $ echo ${VERSION} # 使用-号,如果变量VERSION没有值,就输出默认值; $ echo ${VERSION:-"Default value"} # 使用+号,如果变量VERSION有值,就输出默认值; $ echo ${VERSION:+"Default value"} # 使用=号,如果变量VERSION没有值,就把默认值赋值给变量VERSION; $ echo ${VERSION:="Default value"} # 撤销变量; $ unset VERSION |
11. 截取一个变量的字符串
1 2 3 4 5 6 7 8 9 10 11 12 |
# 显示变量值,一个“#”表示从左往右第一个*/左边的内容都去掉 $ FILE="/lib/modules" $ echo ${FILE#*/} # 显示变量值,两个“##”表示从左往右最后一个*/左边的内容都去掉 $ echo ${FILE##*/} # 显示变量值,一个“%”表示从右往左第一个/*右边的内容都去掉 $ echo ${FILE%/*} # 显示变量值,两个%%表示从右往左最后一个/*右边的内容都去掉 $ echo ${FILE%%/*} |
12. 取一个变量的子串
1 2 3 4 5 6 |
# 2表示偏移过去2个字符,3表示显示至偏移2个之后的3个字符; $ A="Hello world" $ echo ${A:2:3} # 2表示偏移过去2个字符,其余的全部显示; $ echo ${A:2} |
13. 查看变量的字符个数
1 |
$ echo ${#A} |
14. 元字符:元字符是有特殊含义的特殊字符,shell遇到这类字符会先做翻译而不是直接把它们传递给命令
1 2 3 4 5 |
; #在前一个命令结束时,忽略其返回值,继续执行下一个命令; $ #作变量或运算替换; } #将其内的命令至于非命名函数中执行; # #注释(用于shell脚本中); & #重定向到文件描述符,或将命令置于后台执行; |
15. 转义符
{}:花括号是用在当变量名称容易和紧跟其后的其他字符相混淆时
1 2 3 |
$ VERSION="edition" $ echo ${VERSION}edition editionedition |
” “:双引号主要起一个界定字符串的作用当要赋值的内容中包括空格时,不会识别不了
1 2 3 4 5 |
$ VER="version 1.0" $ echo $VER $ CMD="ver $VER" $ echo CMD ver version 1.0 |
‘ ’:单引号表示变量中赋值的内容有$、”、\等特殊含义字符会视为普通字符显示(在单引号范围内不能引用其他的变量、$视为普通的字符)
1 2 3 |
$ A='var $version' $ echo $A var $version |
` `:反撇号用于主要命令替换允许将执行某个命令的屏幕输出的结果赋值给变量、反撇号扩起来的内容必须是能够执行的命令行
1 2 3 |
$ B=`which useradd` $ echo $B /usr/sbin/useradd |
$(): 使用反撇号难以在一行命令中实现嵌套命令替换操作这时可以用$()来代撇号
1 2 |
$ rpm -qf $(which useradd) $ rpm -qi $(rpm -qf $(which useradd)) |
还有如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# \n:换行符,如果使用echo输出时则必须使用echo -e开启转义符支持,默认是关闭的,如: $ echo -e "one\ntow" # \a:让终端发出声音; $ echo -e "one\atow" # \t:水平制表符; $ echo -e "one\ttow" # \v:垂直制表符; $ echo -e "one\vtow" # \:转义符,去除其后紧跟的元字符或通配符的特殊意义,如实现$符号显示; $ echo -e "\$var" # \`:去除反引号的特殊含义; $ echo -e "\"" # \”:去除双引号的特殊含义; $ echo -e "\'" # \\:去除反斜杠的含义; $ echo -e "\\" |
16. 逻辑运算符
1 2 3 |
&& #逻辑“与”运算,只要有一个为false那么结果一定为false; | #逻辑“或”运算,只要有一个位true那么结果一定为true; ! #逻辑“非”运算,只有结果为true时那么最终结果为false,与之相反; |
案例:
1 2 3 4 5 6 7 8 |
# 如果用户存在,就显示用户已存在;否则,就添加此用户; $ id user1 && echo "user1 exists." || useradd user1 # 如果用户不存在,就添加;否则,显示其已经存在; $ ! id user1 &&useradd user1 || echo "user1 exists." # 如果用户不存在,添加并且给密码;否则,显示其已经存在; $ ! id user1 &&useradd user1 && echo "user1" | passwd --stdin user1 || echo "exist" |
17. 支持编程(就是shell脚本编程)