本博客内容来自《Linux命令行与shell脚本编程大全》第五章以及第一章、第二章等部分节选
目录
1、背景
Linux系统分为以下四部分
Linux内核
GNU工具
图形化桌面环境
应用软件
其中GNU工具是由GNU组织(GNU's Not Unix)开发的一套完整的Unix工具,该工具内有一种特殊的交互式工具——shell,为用户提供启动程序、管理文件系统中的文件以及Linux系统上进程的途径,其核心是命令行提示符。所有Linux发行版的shell都是bash shell,这是GNU项目提供的默认版本。
shell提供了文本命令行界面(command line interface,CLI),CLI只接受文本输入,也只能显示出文本和基本的图形输出。
当然,shell不仅仅是一种CLI,而是一个时刻都在运行的复杂交互式程序。
2、shell的类型
系统启动后使用的shell类型可以在/etc/passwd文件中查看,第七个字段即为默认shell程序
[root@izwz9194nuv8g0cwqfqsh3z ~]# cat -n /etc/passwd
1 root:x:0:0:root:/root:/bin/bash
此外,还有一个默认shell是/bin/sh,这个shell主要用于需要在启动时使用的系统shell脚本
[root@izwz9194nuv8g0cwqfqsh3z ~]# ls -lF /bin/bash
-rwxr-xr-x 1 root root 960472 Dec 7 2016 /bin/bash*
[root@izwz9194nuv8g0cwqfqsh3z ~]# ls -lF /bin/sh
lrwxrwxrwx 1 root root 4 Aug 18 2017 /bin/sh -> bash*可以看出在本文所选环境中,/bin/sh通过软链接设置为bash shell
3、shell的父子关系
父shell:用于登录某个虚拟控制器终端或在GUI中运行终端仿真器时所启动的默认交互shell
子shell:在CLI提示符后输入/bin/bash命令或其他等效bash命令时创建的新的shell程序,创建子shell是有代价的
[root@izwz9194nuv8g0cwqfqsh3z ~]# ps -f
UID PID PPID C STIME TTY TIME CMD
root 15419 15417 0 14:07 pts/0 00:00:00 -bash
root 15455 15419 0 14:25 pts/0 00:00:00 ps -f
[root@izwz9194nuv8g0cwqfqsh3z ~]# bash
[root@izwz9194nuv8g0cwqfqsh3z ~]# ps -f
UID PID PPID C STIME TTY TIME CMD
root 15419 15417 0 14:07 pts/0 00:00:00 -bash
root 15456 15419 0 14:25 pts/0 00:00:00 bash
root 15467 15456 0 14:25 pts/0 00:00:00 ps -f上述显示表明第二个ps -f命令是在子shell中运行的,可以用ps --forest查看父子关系
[root@izwz9194nuv8g0cwqfqsh3z ~]# ps --forest
PID TTY TIME CMD
15419 pts/0 00:00:00 bash
15456 pts/0 00:00:00 \_ bash
15474 pts/0 00:00:00 \_ ps
退出子shell采用exit命令
进程列表
-
命令列表
命令列表是将一连串命令用 ; 分号隔开,如下所示,命令依次执行不存在任何问题
[root@izwz9194nuv8g0cwqfqsh3z ~]# pwd; ls; cd tast/; pwd; cd ..; ls
/root
file1 link link_he mod_test tast
/root/tast
file1 link link_he mod_test tast
-
进程列表(存在疑问)
进程列表是在命令列表的基础上增加括号,如下所示,且进程列表执行后会创建子shell
[root@izwz9194nuv8g0cwqfqsh3z ~]# (pwd; ls; cd tast/; pwd; cd ..; ls)
/root
file1 link link_he mod_test tast
/root/tast
file1 link link_he mod_test tast
[root@izwz9194nuv8g0cwqfqsh3z ~]# ps --forest
PID TTY TIME CMD
15419 pts/0 00:00:00 bash
15456 pts/0 00:00:00 \_ bash
15496 pts/0 00:00:00 \_ ps此时进程处于子shell中,然后我发现一个书本上没有提到的很好玩的地方,先输入exit退出子shell,然后执行以下命令
[root@izwz9194nuv8g0cwqfqsh3z ~]# (ps --forest;pwd; ls; cd tast/; pwd; cd ..; ls)
PID TTY TIME CMD
15419 pts/0 00:00:00 bash
15497 pts/0 00:00:00 \_ bash
15498 pts/0 00:00:00 \_ ps
/root
file1 link link_he mod_test tast
/root/tast
file1 link link_he mod_test tast
[root@izwz9194nuv8g0cwqfqsh3z ~]# exit
logout
Connection closing...Socket close.在这里就存在疑问了,按道理我输入exit会退出子shell,但是没有,直接退出系统了,说明我在进程列表开头增加的ps --forest命令虽然是在子shell中执行的,但是执行完之后自动退出了子shell,原因是什么呢?希望知道的朋友留言告诉我一声~
子shell新奇用法
进程列表、协程和管道(后面介绍)都利用了shell
-
后台模式
在后台模式中运行命令可以在处理命令的同时让出CLI,以供他用。可以使&进入后台模式,以sleep为例,如下所示
[root@izwz9194nuv8g0cwqfqsh3z ~]# sleep 10&
[1] 15561
[root@izwz9194nuv8g0cwqfqsh3z ~]# ps -f
UID PID PPID C STIME TTY TIME CMD
root 15506 15504 0 14:45 pts/0 00:00:00 -bash
root 15561 15506 0 15:05 pts/0 00:00:00 sleep 10
root 15562 15506 0 15:05 pts/0 00:00:00 ps -f
[root@izwz9194nuv8g0cwqfqsh3z ~]# ps -f
UID PID PPID C STIME TTY TIME CMD
root 15506 15504 0 14:45 pts/0 00:00:00 -bash
root 15563 15506 0 15:05 pts/0 00:00:00 ps -f
[1]+ Done sleep 10
其中,&符号是进入后台的参数,此外,可以通过jobs命令查看正在后台运行的作业,也可以添加 -l 参数显示更多[root@izwz9194nuv8g0cwqfqsh3z ~]# jobs
[1]+ Running sleep 10 &
-
在后台使用进程列表
要是想在子shell中进行繁重的处理工作,又不想让子shell的I/O受制于终端,可以将进程列表置入后台模式,操作如下
[root@izwz9194nuv8g0cwqfqsh3z ~]# (sleep 2; echo "doing jobs"; sleep 2)&
[1] 15574
[root@izwz9194nuv8g0cwqfqsh3z ~]# doing jobs[1]+ Done ( sleep 2; echo "doing jobs"; sleep 2 )
使用sleep和echo命令的进程列表只是作为一个示例,其实更具有实用意义的命令是tar进行文件归档以上一篇博客中的例子:
#(tar -cvf test.tar test/ test2/)&
这样可以避免在归档大文件时阻塞CLI的情况发生
-
协程命令coproc
协程可以同时做两件事情,在后台生成子shell,并在子shell中执行命令。基本用法如下:
[root@izwz9194nuv8g0cwqfqsh3z ~]# coproc sleep 10
[1] 15586
[root@izwz9194nuv8g0cwqfqsh3z ~]# jobs
[1]+ Running coproc COPROC sleep 10 &其中,COPROC是协程给进程起的名字,存在多个协程时可以自己设置该名字,如下所示
[root@izwz9194nuv8g0cwqfqsh3z ~]# coproc My_Job { sleep 10; }
[1] 15596
[root@izwz9194nuv8g0cwqfqsh3z ~]# jobs
[1]+ Running coproc My_Job { sleep 10; } &注意My_Job与{之间需要空格
使用协程也可以达到在后台使用进程列表的作用
[root@izwz9194nuv8g0cwqfqsh3z ~]# coproc (sleep 2; echo "doing jobs"; sleep 10)
[1] 15643
[root@izwz9194nuv8g0cwqfqsh3z ~]# jobs
[1]+ Running coproc COPROC ( sleep 2; echo "doing jobs"; sleep 10 ) &
[root@izwz9194nuv8g0cwqfqsh3z ~]# ps --forest
PID TTY TIME CMD
15610 pts/0 00:00:00 bash
15643 pts/0 00:00:00 \_ bash
15645 pts/0 00:00:00 | \_ sleep
15646 pts/0 00:00:00 \_ ps
[root@izwz9194nuv8g0cwqfqsh3z ~]# ps --forest
PID TTY TIME CMD
15610 pts/0 00:00:00 bash
15647 pts/0 00:00:00 \_ ps
[1]+ Done coproc COPROC ( sleep 2; echo "doing jobs"; sleep 10 )可以看到,任务在后台执行,且创建了子shell;不过对于用户来说并没有进入子shell,还能愉快的操作父shell,真正实现了任务在后台执行的效果
4、shell的内建命令
外部命令
外部命令又称为文件系统命令,即存在于bash shell之外的程序,通常位于/bin、/usr/bin、/sbin或/usr/sbin中
ps就是一个外部命令,可以用which或type命令找到它
[root@izwz9194nuv8g0cwqfqsh3z ~]# which ps
/usr/bin/ps
[root@izwz9194nuv8g0cwqfqsh3z ~]# type -a ps
ps is /usr/bin/ps
外部命令执行时创建子进程的操作称为衍生,父进程发出外部命令ps -f,衍生出子进程来执行外部命令ps -f。
内建命令
内建命令与外部命令的区别在于不需要创建子进程来执行。如cd和exit等命令都是内建命令,用type可以知道命令的类型,用which只能显示外部命令文件,echo、pwd等既有内建命令又有外部命令,使用type -a可以查看不同实现。
[root@izwz9194nuv8g0cwqfqsh3z ~]# type cd
cd is a shell builtin
[root@izwz9194nuv8g0cwqfqsh3z ~]# type ps
ps is hashed (/usr/bin/ps)
内建命令执行速度更快[root@izwz9194nuv8g0cwqfqsh3z ~]# type -a echo
echo is a shell builtin
echo is /usr/bin/echo想使用echo的外部命令实现,指明对应文件即可 /usr/bin/echo,如
[root@izwz9194nuv8g0cwqfqsh3z ~]# /usr/bin/echo hahha
hahha
-
history命令
history命令是很有用的,可以跟踪你用过的命令,以便唤回并重新使用。默认显示近期输入的1000条命令,如果想要改变这个值的大小,直接为环境变量HISTSIZE赋值,如:HISTSIZE=2000;
[root@izwz9194nuv8g0cwqfqsh3z ~]# history
1 ll
2 ls
3 cd /etc/passwd
4 vim
5 vim /etc/passwd
6 man xterm
7 man .man -help
8 man -help
......(此处省略近千条)如果想重新使用第N条,则执行 !N 即可,例如
......
226 history
227 ps --forest
228 history
[root@izwz9194nuv8g0cwqfqsh3z ~]# !227
ps --forest
PID TTY TIME CMD
15610 pts/0 00:00:00 bash
17664 pts/0 00:00:00 \_ ps如果只想唤回最近的命令,可以输入!!,例如
[root@izwz9194nuv8g0cwqfqsh3z ~]# /usr/bin/echo hahha
hahha
[root@izwz9194nuv8g0cwqfqsh3z ~]# !!
/usr/bin/echo hahha
hahha
历史命令被存储在隐藏文件.bash_history中,位于用户主目录,如下所示
[root@izwz9194nuv8g0cwqfqsh3z ~]# cat .bash_history
ll
ls
cd /etc/passwd
vim
vim /etc/passwd
man xterm
man .man -help
man -help
man man
......
历史命令记录一开始是保存在内存的,如果要强制将其同步至文件,可以执行 history -a
当然,还有一种广为使用的命令搜索方法:
ctrl+r搜索:
在提示符后面,输入,要搜索的关键字:
(reverse-i-search)`':sed
就会自动联想出包含此关键字的历史命令
-
命令别名alias
alias是内建命令,允许为常用命令(及其参数)创建别名,减少输入量
系统已有的别名可以通过命令 alias -p查看
[root@izwz9194nuv8g0cwqfqsh3z ~]# alias -p
alias cp='cp -i'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l.='ls -d .* --color=auto'
alias ll='ls -l --color=auto'
alias ls='ls --color=auto'
alias mv='mv -i'
alias rm='rm -i'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'注意:alias ls='ls --color=auto'表明终端支持彩色模式的列表
alias使用格式即
alias 别名=‘具体的命令组成’
当然,你所起的别名只在当前shell进程中有效(可以让其在子shell中也生效,见下一篇博客)