在其他的一些操作系统中,命令行界面只是对图形化界面的一个补充。作为Linux灵感来源的Unix系统最初没有图形化界面,所有的任务都是通过命令行来完成的。因此,Unix的命令行系统得到了很大的发展,并且成为一个功能强大的系统。Linux系统沿袭了这一特点,许多强大的功能都可以从shell中轻松实现,对自动化简单的任务非常有用。
使用shell进行程序设计的原因之一是,可以快速、简单地完成编程,shell也非常适合于编写一些执行相对简单的任务的小工具,因为它们更强调的是易于配置、易于维护和可移植性,而不是很看重执行的效率,还可以使用shell对进程控制进行组织,使命令按照预定顺序在前一阶段命令成功完成的前提下顺序执行。
虽然shell表面上和Windows的命令提示符相似,但是它具备更强大的功能以完成相当复杂的程序,不仅可以通过它执行命令、调用Linux工具,还可以自己编写程序。shell执行shell程序,这些程序通常被称为脚本,它们是在运行时解释执行的。这使得调试工作比较容易进行,因为可以逐行地执行指令,而且节省了重新编译的时间。然而,这也使得shell不适合用来完成时间紧迫型和处理器忙碌型的任务。
Unix/Linux哲学
Unix结构非常依赖于代码的高度可重用性
ls –al | more
这个命令使用了ls和more工具并通过管道实现了文件列表的分屏显示,每个工具就是一个组成部件,通常可以将许多小巧的脚本程序组合起来以创建一个庞大而复杂的程序。
man bash | col –b | lpr
这个命令打印了bash使用手册的参考副本。
Linux具备自动文件类型处理功能,所以使用工具的用户一般不必了解它们是用哪种语言编写的。如果想要这些工具运行得更快,常见的做法是首先在shell中实现工具的原型,一旦确定值得这么做,然后再用C或C++、Perl、Python或者其他执行得更快速的语言来重新实现它们。相反,如果在shell中这些工具工作得已足够好,就不必再重新实现它们。
是否需要重新实现脚本程序取决于是否需要对其进行优化,是否需要将程序移植到其他系统,是否需要让其更易于修改以及它是否偏离了其最初的设计目的。
Linux系统中已经装有很多shell脚本例子,包括软件包安装程序、.xinitrc和startx文件以及/etc/rc.d目录中用于启动时配置系统的脚本程序。
shell是一个作为用户与Linux系统间接口的程序,允许用户向操作系统输入需要执行的命令,与Windows的命令提示符类似,但是Linux shell的功能更强大。例如,可以使用<和>对输入输出进行重定向,使用|在同时执行的程序之间实现数据的管道传递,使用$(…)获取子进程的输出。
可以使用“/bin/bash --version”来查看bash的版本号。
不同种类的shell:
1、sh(Bourne)
源于Unix早期版本的最初的shell
2、csh、tcsh、zsh
Cshell及其变体,最初是由Bill Joy在BerkeleyUnix上创建的,可能是继bash和Korn shell之后第三个最流行的shell
3、ksh、pdksh
korn shell和其公共域兄弟pdksh由David Korn编写,是许多商业版本Unix的默认shell
4、bash
来自GNU项目的Bourne Again Shell是Linux的主要shell,可以免费获取其源代码
管道和重定向
把ls命令的输出保存到文件lsoutput.txt中:
ls –l > lsoutput.txt
文件描述符0代表一个程序的标准输入,文件描述符1代表标准输出,文件描述符2代表标准错误输出,可以单独地重定向其中任何一个,还可以重定向其他文件描述符。
上面的例子通过>操作符把标准输出重定向到一个文件。在默认情况下,如果该文件已经存在,它的内容将被覆盖。如果要改变默认行为,可以使用命令set –o noclobber(set -C)命令设置noclobber选项,从而阻止重定向操作对一个已有文件的覆盖,并且可以使用set +o noclobber命令取消该选项。
将ps命令的输出附加到指定文件的尾部:
ps >> lsoutput.txt
如果想对标准错误输出进行重定向,需要把重定向的文件描述符编号加在>操作符的前面。因为标准错误输出的文件描述符标号是2,所以使用>2操作符。当需要丢弃错误信息并阻止它显示在屏幕上时,这个方法很有用。
假设用kill命令在一个脚本程序里终止一个进程,如果kill执行之前,进程已经结束,那么在默认情况下,kill命令会向标准错误输出写一条错误信息,显示在屏幕上。通过对标准输出和标准错误输出都进行重定向,可以阻止kill命令向屏幕上写任何内容。
把标准输出和标准错误输出分别重定向到不同的文件:
kill –HUP 1234 >killout.txt 2>killer.txt
把两组输出都重定向到一个文件中:
kill -1 1234 >killouterr.txt 2>&1
(将标准输出重定向到文件killouterr.txt,然后将标准错误输出重定向到与标准输出相同的地方)
因为可以通过返回码来了解kill命令的执行结果,所以通常并不需要保存标准输出或标准错误输出的内容,可以用Linux的通用“回收站”/dev/null来有效丢弃所有的输出信息:
kill -1 1234 >/dev/null 2>&1
重定向标准输入:
more < killout.txt
(在Linux下这样做意义不大,因为more命令可以接受文件名作为参数)
可以用管道操作符|来连接进程,Linux与MS-DOS不同,在Linux下通过管道连接的进程可以同时运行,并且随着数据流在它们之间的传递可以自动地进行协调。
使用sort命令对ps命令的输出进行排序:
(不使用管道)
ps > psout.txt
sort psout.txt > pssort.out
(用管道来连接进程)
ps | sort > pssort.out
如果想在屏幕上分页显示输出结果,可以再连接第三个进程more:
ps | sort | more
允许连接的进程数目是没有限制的。
查看系统中运行的所有进程的名字,但不包括shell本身:
ps –xo comm | sort | uniq | grep –v sh | more
(首先按字母顺序排序ps命令的输出,再用uniq命令去除名字相同的进程,然后用grep –v sh命令删除名为sh的进程,最终将结果分页显示在屏幕上)
有一点需要引起注意:如果有一系列的命令需要执行,相应的输出文件是在这一组命令被创建的同时立刻被创建或写入的,所以决不要在命令流中重复使用相同的文件名。
如果执行如下命令:
cat mydata.txt | sort | uniq >mydata.txt
最终将得到一个空文件,因为读取文件mydata.txt之前就已经覆盖了这个文件的内容。
编写shell脚本程序有两种方式:
1、输入一系列命令让shell交互地执行
2、把命令保存在一个文件中,将文件作为一个程序来调用
从大量C语言源文件中查找包含字符串POSIX的文件:
for file in *
do
if grep –l POSIX $file
then
more $file
fi
done
(grep命令输出找到的包含POSIX字符串的文件,然后more命令将文件的内容显示在屏幕上,最后返回shell提示符)
shell提供通配符扩展(globbing),使用通配符*来匹配一个字符串,使用通配符?来匹配单个字符,[set]允许匹配方括号中任何一个单个字符,[^set]对方括号中的内容取反——匹配任何没有出现在给出的字符集中的字符,扩展的花括号{}(只能用在包括bash的部分shell中)允许任何的字符串组放在一个集合中,以供shell进行扩展。
列出文件my_fingers和my_toes:
ls my_{finger,toe}s
更有效的方式:
more `grep –l POSIX *`
或者:
more ${grep –l POSIX *}
输出包含POSIX字符串的文件名:
grep –l POSIX * | more
创建脚本:
#!/bin/bash
#first
for file in *
do
if grep –q POSIX $file
then
echo $file
fi
done
exit 0
#!字符告诉系统同一行上紧跟它后面的参数是用来执行本文件的程序。考虑向后兼容,路径按惯例最好不要超过32个字符。
exit命令确保脚本程序能够返回一个有意义的退出码,当程序以交互方式运行时,很少需要检查退出码,但如果打算从另一个脚本程序里调用这个脚本程序并查看是否执行成功,返回一个适当的退出码就很重要,所以应该在退出时返回一个合理的退出码。
一般情况下,Linux和Unix很少利用扩展名来决定文件的类型,可以使用file命令来检查文件类型。
运行脚本文件:
/bin/bash shellfilename
或者使用chmod命令来改变文件的模式:
chmod +x shellfilename
运行:
1、PATH=$PATH:.
2、编辑.bash_profile文件,将1中的命令添加到文件末尾,退出登录在重新登录
3、shellfilename
或者使用./shellfilename命令运行。
使用./指定路径能够保证不会意外执行系统中同名的命令。
系统管理员设置文件属主和访问权限:
# cp shellfilename /usr/local/bin
# chown root /usr/local/bin/shellfilename
# chgrp root /usr/local/bin/shellfilename
# chmod 755 /usr/local/bin/shellfilename
或者使用chmod更明确的格式:
# chmod u=rwx,go=rx/usr/local/bin/shellfilename
在Linux系统中,如果拥有包含某个文件的目录的写权限,就可以删除这个文件。目录只是另一种类型的文件,拥有对一个目录文件写权限的用户可以添加和删除目录文件中的名称(文件)。