
什么是 Shell
这应该是个蛮有趣的话题:『什么是 Shell ?』相信只要摸过电脑,对于作业系统(不论是 Linux 、 Unix 或是 Windows )有点概念的朋友们大多听过这个名词,因为只要有『作业系统』那么就离不开 Shell 这个东西。但是,在讨论 Shell 之前,我们先来了解一下电脑的运作状况吧!举个例子来说:当您要电脑传输出来『音乐』的时候,您的电脑需要什么东西呢?
1. 当然就是需要您的硬体有『音效卡晶片』这个硬体配备,否则怎么会有声音;
2. 作业系统的核心能够支援这个晶片组,当然还需要提供晶片的驱动程式?;
3. 需要使用者(就是您)输入发生声音的指令?!
这就是基本的一个输出声音的需要的步骤!那么也就是说,您必须要『输入』一个指令之后,『硬体』才会透过您下达的指令来工作!嘿嘿!那么硬体怎样知道您下达的指令呢?那就是 kernel (核心)的控制工作了!了解了吗?没错!也就是说,我们必须要透过『 Shell 』将我们输入的指令和 Kernel 沟通,好让 Kernel 能够控制硬体来正确无误的工作!基本上,我们能够透过底下这两张图来说明一下:
基本上,替我们工作的是『硬体』,而控制硬体的是『核心』,再来,我们使用者乃是利用『Shell』控制一些 kernel 提供的 『工具 Utility』来操控硬体替我们正确的工作。再举个例子来说,当我们使用 shell 的功能,输入『 cd /』来转换目录时, shell 便利用 kernel 提供的 cd 工具来告诉 kernel 转换硬碟的工作目录到 / 当中,然后硬碟就根据 kernel 的掌控而转换到 / 当中?!这个就是 Shell 的主要功能?!再进一步来说,由于 kernel 听不懂人类的语言,而人类也没有办法直接记得 kernel 的语言,所以两者的沟通就得藉由 shell 来支援了!
以字面上的意思来说, kernel 是『核心』的意思,而 Shell 是『壳』的意思,呵呵!也就是说, shell 是最外头的咚咚!而 kernel 乃是最内层的的咚咚啦!核心是作业系统的最底层的东西!这个核心里头包括了各种的支援硬体的工具!当然?,假如您的硬体太新,而您的 kernel 并没有支援的话,那么很抱歉,您的 Shell 能力再怎么强,也没有办法使硬体工作的!这样能够了解了吗?呵呵!没错!使电脑主机工作的正是核心的任务,但是操作核心来替使用者工作的,却是 shell 喔!因此,有时候您的 shell 搞了老半天,硬体却不能工作的时候,请注意,您的『核心』是否正确呢?阿!扯远了!这是 kernel 章节才要说的东西~~
BASH Shell
知道什么是 Shell 之后,那么我们来了解一下 Linux 使用的是哪一个 shell 呢?什么!哪一个?难道说 shell 不就是『一个 shell 吗?』哈哈!那可不!由于早年的 Unix 年代,发展者众,呵呵!所以由于 shell 依据发展者的不同就有许多的版本,例如常听到的 Bourne SHell (sh) 、在 Sun 里头预设的 C SHell、 商业上常用的 K SHell、, 更有 TCSH 等等,每一种 Shell 都各有其特点。至于 Linux 使用的这一种版本就称为『 Bourne Again SHell (简称 bash ) 』,这个 Shell 是 Bourne Shell 的增强版本,也是基准于 GNU 的架构下发展出来的呦!
在介绍 shell 的长处之前,先来说一说 shell 的简单历史吧:第一个流行的 shell 是由 Steven Bourne 发展出来的,为了纪念他所以就称为 Bourne shell ,或直接简称为 sh !而后来另一个广为流传的 shell 是由柏克莱大学的 Bill Joy 设计依附于 BSD 版的 Unix 系统中的 shell ,这个 shell 的语法有点类似 C 语言,所以才得名为 C shell ,简称为 csh !由于在学术界 Sun 主机势力相当的庞大,而 Sun 主要是 BSD 的分支之一,所以 C shell 也是另一个很重要而且流传很广的 shell 之一(因为太多的程式设计师使用的就是 C 语言啦!)!
好了,那么 BASH 是怎么一回事呢?这个 shell 是 GNU 计画中重要的工具软体之一,现在也是 GNU 作业系统中标准的 shell ,他主要相容于 sh 。所以,可想而知的,现在几乎任何的 Linux distribution 都是使用 bash 作为管理核心的主要 shell ?!那么这个 shell 有什么好处,干嘛 Linux 要使用他作为预设的 shell 呢? BASH 主要的长处有底下几个:
? 命令编修能力(类似 DOS 的 doskey 功能):使用 bash 里头,个人认为相当棒的一个功能就是『他能记忆使用过的指令!』这功能真的相当的棒!因为我只要在指令列按『上下键』就能够找到前一个输入的指令!而预设的指令记忆功能能够到达 1000 个!也就是说,您曾下达过的指令都被记录下来了,记录的档案在您的家目录内的 .bash_history !至于这一次登入所执行的指令都被暂存在暂存区中,成功的登出系统后,该指令记忆才会记录到 .bash_history 当中!这有什么功能呢?最大的好处就是能够『查询曾做过的举动!』,如此能够知道您的执行步骤,那么就能够追踪您曾下达的指令,以作为除错的工具!但如此一来也有个烦恼,就是假如被骇客入侵了,那么他只要翻您曾执行过的指令,刚好您的指令又跟系统有关(例如直接输入 MySQL 的密码在指令列上面)那么很容易就被破解您的 Linux 主机!所以,最好是将记录的指令数目减小一点较好!
?档案比对补全功能(比对资料正确性):这个功能也相当的棒!假如在执行命令的时候不想按下太多的按键,例如指令 pcprofiledump 够长吧!好了,那么假如您输入了 pcprofile 之后,再按下 [Tab] 按键的话,那么 bash 马上会自动的将后面的 dump 接上来!那假如有重复的指令呢?那么按下两次 [Tab] 将会把任何重复的指令给他列出来?!
o直接在指令列按下 [Tab][Tab] 两次,那么 Linux 将会把系统内的任何执行档列出来;
另外一个长处就是,能够将该指令所进行的 parameter (和路径或档案相关的)比对后,列出正确的项目!举个例子来说,假如我要列出 /etc/sysconfig/network-scripts 里面的任何档案时,要怎样下达参数?
o ls -al /etc/sysconfig/network-scripts
那我能够在输入到 network 时按下 [Tab] 按键,则 -scripts 就会被自动的加入命令列了!反正真的是蛮方便的,有事没事多按[tab] 按键是不错的一件事呦!
?命令别名(alias)设定功能:假如我需要知道这个目录底下的任何档案(包含隐藏档)及任何的档案属性,那么我就必须要下达 ls -al 这样的指令列,唉!真麻烦,有没有更快的取代方式?呵呵!就使用命令别名呀!例如我最喜欢直接以 lm 来取代上面的命令,也就是说, lm 会等于 ls -al 这样的一个功能,嘿!那么要怎样作呢?就使用 alias 即可!您能够在指令列出入 alias 就能够知道现在的命令别名有哪些了!也能够直接下达命令来设定别名呦:
oalias lm=’ls -al’
?工作控制 (jobs)、前景背景控制:这部分我们在之后的 指令篇会再提及!使用前、背景的控制能够让工作进行的更为顺利!至于工作控制(jobs)的用途则更广,能够让我们随时将工作丢到背景中执行!而不怕不小心使用了 [Ctrl] + C 来停掉该程式!真是好样的!
?Shell scripts 的强大功能:在 DOS 年代还记得将一堆指令写在一起的所谓的『批次档』吧?在 Linux 底下的 shell scripts 则发挥的更为强大的功能,能够将您日常生活当中常需要下达的连续指令写成一个档案,该档案并且能够透过对谈互动式的方式来进行主机的侦测工作!也能够藉由 shell 提供的环境变数及相关指令来进行设计,哇!整个设计下来几乎就是个小型的程式语言了!该 scripts 的功能真的是超乎我的想象之外!以前在 DOS 底下需要程式语言才能写的东西,在 Linux 底下使用简单的 shell scripts 就能够帮您达成了!真的利害!!这部分我们在底下再来谈!
在了解了 BASH 的长处之后,再来我们要来讨论的是:那怎样在 Shell 提供的环境中下达指令呢?其实很简单的,下达指令的方式为:
很简单吧!OK!那么再来一个问题:『Shell 是什么时候开始接管 Linux 主机的!?』假如您对于鸟哥前面提到的『开机流程』有稍微去了解一下的话,那么应该能够了解到 Linux 经由 Kernel 执行完毕,并且执行了 init 和 run-level 设定的一些 scripts 之后,接下来执行了 login 的程式,就能够顺利的进入到 shell 接管的程式了!当然?,要等到使用者顺利的登入 Linux 之后,才能够使用 shell 来进行和主机沟通的动作呦!另外,需要注意的是,登入主机之后通常使用者的起始目录会在『家目录』, root 的家目录预设在 /root 底下,一般使用者的家目录则和 /etc/passwd 的设定有关!
变数和变数的设定:echo, env, set, 变数设定规则, export, unset,
再继续研究 BASH 之前,我们要就变数这个东西来讨论一番,因为在主机里面有太多的资料需要进行存取了,而这些资料都是一些服务所必须的,例如 mail 的存取路径在 /var/spool/mail 、家目录预设在 /home/useraccount 等等,当然我们能够改变这些个变数,但是假如该变数是直接深植于套件当中,那么当您修改了某些参数之后,嘿嘿!您的套件就必须要『由源代码直接更新再编译』才行!这样似乎很麻烦,所以?,就会有变数这个好东西出来了!
举个简单的例子来说, sendmail 的 smtp 存放 mail 路径是经由 /etc/profile 里头的 MAIL="/var/spool/mail/$USER"来设定的,而当我修改了上面这一个咚咚,然后重新开机之后,嘿嘿嘿嘿!我的邮件就能够存放到不同的路径去了!而且不会有问题!能够顺利的『在 Linux 主机上面』收发。然而问题发生在 pop3 这个服务上面,由于 pop3 的预设路径是在 source code 里头,而且就正是 /var/spool/mail 这个路径,也就是说,不论我怎么修正我的『变数』, pop3 都不为所动!唉~真惨,所以就无法直接以 pop3 来收信了(例如 OutLook 就不能工作了)!会发生密码不接受的问题呢!
此外,例如我们在执行程式的时候,系统怎么知道您的 ls 这个指令放在哪里?原来是有 PATH 这个变数,系统会透过这个变数里面所设定的路径去依序寻找该指令系统,假如很难找到的话,那么才在萤幕上显示『 command not found 』字样!这些还都只是系统预设的变数的目的,假如是个人的设定方面:例如您要写一个大型的 script (批次档)时,有些资料因为可能由于使用者习惯的不同而有差异(例如路径!),而由于该内容使用在 script 的地方相当的多,假如每次都需要修改该地方,则一定会疯掉!这个时候使用变数,而将该变数的定义写在最前面,嘿嘿!那么您只要修改一行就等于修改整篇 script 了!方便的很!所以,良好的程式设计师都会善用变数的定义!(这个部分我们在底下还会再提到!)
假如说的学理一点,那么由于在 Linux System 下面,任何的执行续都是需要一个执行码,而就如同上面提到的,您『真正以 shell 来跟 Linux 沟通,是在正确的登入 Linux 之后!』这个时候您就有一个 bash 的执行程式,也才能够真正的经由 bash 来跟系统沟通?!而在进入 shell 之前,也正如同上面提到的,由于系统需要一些变数来提供他资料的存取(或是一些环境的设定参数值,例如是否要显示彩色等等的),所以就有一些所谓的『环境变数』需要来读入系统中了!
说了那么久,那么到底『什么是变数』呢?简单的说,『变数就是以一组文字或符号等,来取代一些设定或是一串保留的资料!』,例如:『VBird』就是『鸟哥』,所以当您读取 VBird 的时候,系统自然就会知道!哈!那就是鸟哥!最简单的例子能够取 PATH 来说明!假如您对于『相对路径和绝对路径』更有点印象的话,那么应该晓得『要下达正确的指令,应该需要指定路径和档名』才行!例如您的 ls 指令应该需要以『/bin/ls』来下达指令才对,那么为何您在任意的路径下都能够执行 ls 呢?而无需指定路径呢?这是因为系统已预设了一些『搜寻路径(PATH)』了,所以当您需要执行一些指令的时候,系统就会依照该 PATH 的设定来进行指令的搜寻!而这个 PATH 就是所谓的变数了!那么怎样『显示变数』呢?这就需要使用到 echo 这个指令啦!
?echo
显示变数内容
语法:
就如同上面的范例,当我们要显示现在的 PATH 这个变数时,使用了 echo ,而为了要分辨是否为变数,那么 Linux 系统预设变数名称前面会加上一个『 $ 』符号,所以就必须要写成 echo $PATH ?!
?有多少的环境变数呀?使用 env 和 set 来看看:
这是我们比较有兴趣的,那就是有多少的环境变数在 Linux 系统中呢?呵呵!您能够简单的使用 env 就能够知道?!『基本上,在 Linux 预设的情况中,使用{大写的字母}来设定的变数一般为系统内定需要的变数』,底下列出 Red Hat 7.2 预设的变数内容:
?env
显示现在系统中主要的预设变数内容
语法:
env 这个指令主要在将现在系统中的主要变数读出来!但是我加上了 sort 就能够将资料进行排序?!所以像上面的 PATH, USER, HOME 等等的资料就会被读出来?!除了 env 这个指令之外,更有一个能够将现在系统中任何的变数资料都读出来的指令,称为 set !set 除了会将上面的资料都给他读出来之外,还会有额外的这些资讯也一起读入(通常都和使用者的设定有关!):
?set
显示现在系统中全部的变数内容
语法:
使用 set 除了会将系统的预设值秀出来之外,连带的任何的您自己设定的变数也会被秀出来!同时需要注意的是,若当时有相当多人同时在线上的话,那么您的变数只能给自己使用(除非改的是系统的预设参数档,如 /etc/profile ),而不会干扰到别人的!就如同前面所说的,由于您登入 Linux 之后会取得一个 PID ,而您的设定将只对这个 PID 和子程式有关!此外,这次登入所进行的变数设定,假如没有更动到设定档,那么这次设定的变数在下次登入时将被取消掉(因为程式 PID 不见?!)!所以?,假如您想要您的变数每次都能在您登入的时候自动就设定好了,那么就必须将您的设定写入登入时载入的设定档!
? 变数设定规则:
好了,我们知道了一些系统的预设变数了,但是假如是我自己想要设定一些我自己的变数,该怎样设定呢?有什么规则需要遵守?呵呵!在说明之前,可能要来让大家了解一下为什么自己会想来设定变数?
我的案例一:最简单的例子就是『路径名称』?!以鸟哥为例,我的工作在 Unix 系统之下进行一些数值模式的模拟工作,偏偏由于资料量太大,为了怕日后忘记这个目录的内容和主要的意义,所以我的档名都取的很长,偏偏在执行模式的过程中,常常会转换目录!我哩ㄌㄟ,光是打那几行路径名称就快要疯掉了!所以我就设定那几行目录名称成为一个四个字元的变数,如此一来我只要输入『 cd $VARI 』这个指令,嘿嘿!马上就移动到该路径下了!很方便吧!当然变数的意义还不止于此,但是这是最简单的实例说明?! 我的案例二:另外一个常常需要变数的咚咚是在 scripts 里面,例如我写的一个侦测登录档的小程式 logfile.sh 这个咚咚,由于里头常常需要用到『储存路径』,偏偏可能每个人的存取路径都不太相同,而假如要修改存取路径的话,嘿嘿!好几十行要同时修改呢!还可能会改错!那么我只要定义一个变数,然后后续的任何资料都使用这个变数的内容!嘿嘿!那么只要大家修改了这个变数的内容(只要一行),后续的动作就无需修正了!这个动作常在程式或是 script 当中看到的!
所以?,有很多的时候为了方便或是使用于 scripts 的意义,我们必须要设定变数!然而在 bash 底下的变数设定是有一定规则的,必须要来遵守才行:
1. 变数和变数内容以等号来连结;
2. 等号两边不能直接接空白字元;
3. 变数名称只能是英文字母和数字,但是数字不能是开头字元;
4. 若有空白字元能够使用双引号『 " 』或单引号『 ’ 』来将变数内容结合起来,但须要特别留意,双引号内能够保有变数,但是单引号则仅为一般字元;
5. 必要时需要以跳脱字元『 \ 』来将特别符号(如 Enter, $, \, 空白字元, ’ 等)变成一般符号;
6. 若该变数为扩增变数内容时,则需以双引号及 $变数名称如:『 "$PATH":/home』继续累加内容;
7. 若该变数需要在其他子程式执行,则需要以 export 来使变数能够动作,如『export PATH』;
8. 通常大写字元为系统预设变数,自行设定变数能够使用小写字元,方便判断(纯粹依照使用者兴趣和嗜好);
9. 取消变数的方法为:『unset 变数名称』。
底下我们举几个例子来说明一下:
根据上面的案例您能够试试看!就能够了解变数的设定?!这个是很重要的呦!请勤加练习!!
bash shell 的设定档案: alias(设定命令别名), history, !command, source,
终于来到 bash 的设定档案?!这部份我们预计分成『系统设定值』和『一般各人喜好设定值』来说明,除非您是 root ,并且对于大家的喜好有一起的认知,否则只要设定您的『个人设定值』(在每个人的家目录内)也就能够?!
? 系统设定值:
所谓的系统设定值,也就是说每个使用者进入到 bash shell 之后,会先读取的设定档案!预设的设定档案有下列几个:
o /etc/profile:这个档案设定了几个重要的变数,例如:『PATH、USER、MAIL、HOSTNAME、HISTSIZE』等等,也同时规划出 inputrc 这个档案的资料内容,您能够在这里设定总体的 PATH 等等的资讯!同时,这个 file 也规划出 /etc/profile.d 及 /etc/inputrc 这两个档案,其中, inputrc 是用在 history (历史指令)的作用上的!总之,您能够了解到刚刚我们学会的变数设定方式,在这个档案中也能够设定呢!但是设定上需要特别小心,因为任何的使用者皆会使用到这个档案的资讯。注:通常我都喜欢将 /usr/local/bin 这个路径加成最前面,这是因为通常自己安装的套件自己最喜欢,所以当然是最先收寻?! ^_^!此外,请注意一下,能够将 HISTSIZE 的大小改变一下,改成 50 就能够啦!比较安全!
o /etc/bashrc:这个档案在规划 umask 的功能,也同时规划出提示字元的内容(就是里头那个 PS1 啦!)。
o /etc/man.config:这个档案或许跟 bash shell 较没相关性,但是对于系统管理员来说,却也是很重要的一个档案!这的档案的内容『规范了使用 man 的时候, man page 的路径到哪里去寻找!』所以说的简单一点,这个档案规定了下达 man 的时候,该去哪里查看资料的路径设定!那么什么时候要来修改这个档案呢?假如您是以 tarball 的方式来安装您的资料,那么您的 man page(指令说明档案)可能会放置在 /usr/local/softpackage/man 里头,那个 softpackage 是您的套件名称,这个时候您就得以手动的方式将该路径加到 /etc/man.config 里头,否则使用 man 的时候就会很难找到相关的说明档?!
这就是系统在设定的时候常常会使用的档案!需要特别留意的是,通常设定完了这几个档案之后,都需要先 logout 在 login 之后才会将设定整个启动起来!
? 个人设定值
那么个人的喜好设定在哪里?嘿嘿嘿嘿!那就是在个人家目录的几个隐藏档当中?!分别会使用到底下的几个档案啦!(注意!都是隐藏档,需要使用 ls -al 方能显示出来),另外,注意一下?!底下那个『 ~ 』代表的是『家目录』的意思!
o ~/.bash_profile:里面定义了个人化的路径(PATH)和环境变数的档案名称!您能够在这里修改您的个人路径呦!当然?!也能够在 ~/.bashrc 这个个人设定的变数里头修改!
o ~/.bashrc:这个档案对于个人喜好的 bash 设定来说,是最重要的啦!因为我都是在这里设定我的个人化变数!例如命令别名的设定!路径的重新定义等等,都是在这里完成的!底下我们再仔细的讨论一下怎样设定命令别名吧!
o ~/.bash_history:这个档案的用途在于将您曾使用过的命令记录下来,而当您再次的以上下键搜寻或直接以 history 搜寻的时候,就能够找到曾使用过的指令?!需要注意的是:
1. 在这一次的执行过程中的指令,将在您离开 shell 之后才会被纪录到这个档案中,否则将只会先被写到暂存记忆体中(Cache);
2. 能够藉由 history 这个指令来将里头的纪录搜寻出来;
3. 这个档案的指令记录笔数,和 HISTFILE 有关,您能够自行在 ~/.bashrc 里头设定,或直接由 root 在 /etc/profile 里面统一设定大小!
o ~/.bash_logout:这个档案则是在『您登出 shell 的时候, BASH 会为您所做的事情!』通常预设是只有 clear 这件事情而已,但是,您也能够将一些备份或是其他您认为重要的工作写在这个档案中(例如清空暂存档),那么当您离开 Linux 的时候,就能够解决一些烦人的事情?!
大致上的个人设定就是如同上面说的!但是,我个人觉得比较重要的是 ~/.bashrc 这一个档案!我喜欢将自己的相关设定写在里头!这样能够很轻易的将个人的设定写好!尤其是命令别名和变数的设定等等!底下我们先来谈一谈『命令别名』和『历史指令记录』这两个东西,然后再来谈 ~/.bashrc 这个档案的一般各人喜好设定!
?命令别名:
命令别名是个很有趣的东西,特别是您的惯用指令特别长的时候!更有,预防一些不小心误杀档案的情况发生的时候!举个例子来说,假如您要查询隐藏档,并且需要长的列出和一页一页翻看,那么需要下达『 ls -al | more 』这个指令,我是觉得很烦啦!要输入好几个单字!那可不能够使用 lm 来简化呢?!当然能够,您能够在命令列下面下达:
[test @tset test]# alias lm=’ls -al | more’
要注意的是:『alias 的定义规则和变数定义规则几乎相同』,所以您只要在 alias 后面加上您的{『别名』=’指令 参数’ },以后您只要输入 lm 就相当于输入了 ls -al|more 这一串指令!很方便吧!另外,我们知道 root 能够移除( rm )任何资料!所以当您以 root 的身份在进行工作时,需要特别小心,但是总有失手的时候,那么 rm 提供了一个参数来让我们确认是否要移除该档案,那就是 -i 这个参数!所以,您能够这样做:
[test @tset test]# alias rm=’rm -i’
嘿嘿!那么以后使用 rm 的时候,就不用太担心会有错误删除的情况了!这也是命令别名的长处?!那么怎样知道现在有哪些的命令别名呢?就使用 alias 呀!
[test @tset test]# alias
alias l.=’ls -d .[a-zA-Z]* --color=tty’
alias ll=’ls -l’
alias lm=’ls -al’
alias ls=’ls --color=tty’
alias which=’alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde’
? 至于假如要取消命令别名的话,那么就使用 unalias 吧!
? 历史指令记录资料:
前面我们提过 bash 有提供指令历史的服务!那么怎样查询我们曾下达过的指令呢?就使用 history ?!
o history, !command
显示历史指令记录内容, 下达历史纪录中的指令
语法:
说明:
基本上 history 的用途很大的!但是需要小心安全的问题!尤其是 root 的历史纪录档案,这是 Cracker 的最爱!因为不小心的 root 会将很多的重要资料在执行的过程中会被纪录在 ~/.bash_history 当中,假如这个档案被解析的话.....而使用『 ! 』配合曾使用过的指令下达是很有效率的一个指令方法!
鸟哥的常用的个人喜好设定值:
底下是 VBird 最喜欢的设定值?!大家能够随意的参考看看就好了!
[test @test test]# vi .bashrc
# .bashrc
# User specific aliases and functions
PATH="/usr/local/bin:/usr/local/sbin:/bin:/sbin:/usr/sbin:/usr/bin:$PATH" <==常用!
export PATH
alias rm=’rm -i’
alias cp=’cp -i’
alias mv=’mv -i’
alias ll=’ls -l’
alias lm=’ls -al|more’ <==常用!
alias h=’history’<==常用!
# Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi
[test @test test]# source ~/.bashrc<==???改的?料直接?入?一次的程式?中!不需登出!
? 当然更有一些个人比较常用的变数,这里就不列出来了!那么改写完毕之后。此外,通常我们改写的这些设定,必须要登出再登入才能被启用!但是我们能够使用 source 来直接的启用他!这也是很多朋友为了因应不同的软体或是其他的执行环境,而写了不同的环境设定档案(不一定是 .bashrc 这个档案),然后在需要的时候再以 source 来将设定读出来即可!这个指令可也是相当重要的呦!
万用字元和特别符号
由于在 bash 当中常会使用到一些万用字元,和搭配特别符号来将指令做更好的利用(例如最常提到的正规表示法 Regulare Express )!底下我们列出一些常用的万用字元和特别符号!
上面的万用字元当中,最常用的就属 *, ?, [] 及 ` 了!我们提几个简单的例子:
[test @test test]# ls test* <==那? * 代表後面不?接??字元都予以接受(?有字元也接受!)
[test @test test]# ls test? <==那? ? 代表後面『一定』要接『一?』字元
[test @test test]# ls test??? <==那? ??? 代表『一定要接三?』字元!
[test @test test]# cp test[1-5] /tmp <==? test1, test2, test3, test4, test5 若存在的?,就拷?到 /tmp 下
[test @test test]# cd /lib/modules/`uname -r`/kernel/drivers <==被 ` ` 括起?的?容『?先?行』!
上面几个例子相当的有趣!尤其是最后面两个!需要注意的是, [] 里面『代表只有一个字元』但是范围能够由 1-5 ,这样来说的话,那么我们假如允许『大写字元』就能够将档案 copy 出来的话,能够这样做:
cp *[A-Z]* /tmp
很有趣吧?! ^_^
此外,那个 `` 里面的『指令』会先被执行,也就是说:
1. 系统先执行 uname -r 找出输出的结果;
2. 将结果累加在目录上面,来执行 cd 的功能!
很棒吧!!这些基本的功能需要特别来了解一下才行呦!
绝对路径和相对路径
其实,在使用 bash 更有另一个困扰,就是当您的 PATH 没有设定完整的时候,下达指令都是要以『一长列的指令连带根目录都要列出来』,呵呵那就是绝对路径的设定法啦!基本上,这个『绝对路径』和『相对路径』的观念是很重要的!否则您将常常会很难找到档案说!所谓的『绝对路径』就是以根目录开始写入到档案的一种命令写定方法,举例来说,我现在在 /home/test 这个 test 使用者的家目录中,我想要看看里面的 .bashrc 这个档案的资料,使用的是 more 这个指令,而这个指令在 /bin/more 当中,则正确的下达指令的方法为:
[test @tset test]# /bin/more .bashrc <==我在的目录为 /home/test !这是绝对路径写法!
而假如您还记得我们在 档案系统指令 那一篇文章中提到的观念的话,那么应该记得使用 ls -al 时会出现两个一定存在的目录,分别是『.』和『..』,分别代表是『这个路径』,和『上一层路径』!
[test @tset test]# ls -al
total 728
drwx------3 vbirdvbird4096 May 19 14:53 . <==?一?路?的?性?明
drwxr-xr-x3 root root 4096 May 5 16:50 .. <==上一?路?的?性?明
以下略!
所以说,要执行上一层目录中的命令,能够下达『 cd ../command 』那个 command 指的是存在的可执行档!那么我因为在 /home/test 里面,距离 /bin 有两层上层目录,所以我要使用 /bin/more 这个执行档,并且使用相对路径的方法,就必须使用:
[test @tset test]# ../../bin/more .bashrc<==一层一层回到根目录,在进入 /bin 的写法!相对路径
这种相对路径的方法相当广泛的被运用于 script 当中,这是因为如前面提到的,每个人的安装预设的目录都不相同,则使用相对路径的话,很容易就能够找到套件之间相依软体或是设定档案的相关性!
关于路径搜寻的问题!为何不执行现在所在目录下的档案?咦!刚刚不是提到『.』和『..』吗?那么那个『 . 』是干嘛用的?!眼尖的朋友应该已发现了,就是『我在执行档案的时候,基本上,并不会主动搜寻现在目录下的档案』举个例子来说,我安装的 squid 这个执行档在 /usr/local/squid/bin/squid 这个档案,然而我在 /usr/local/squid/bin 下达 squid 的时候,系统会告诉您『查不到这个档案!』真是见鬼了!明明有这个档案的呀!这是因为系统预设的 PATH (路径)并没有执行现在目录下的设定,也就是『.』这个路径!您能够使用『 echo $PATH 』看看,就能够知道为什么了!那么为何不要设定这个路径呢?这是因为『安全』的考量。由于系统预设是允许任何人在 /tmp 底下写入任何档案的,那么万一有居心不良的使用者或是 Cracker 入侵您的电脑,并在您的 /tmp 里头埋了一个小木马,并取名为 ls ,好了,改天您以 root 身份登入后,到 /tmp 底下,并执行 ls ,您看会有什么结果?!这个 /tmp/ls 由其他身份的人来执行或许没有问题,但是由 root 来执行却可能会导致 Cracker 所乐意见到的结果!那晓得为何了吧?!当然?!您还是能够选择在 ~/.bashrc 当中设定您的 . 在您的 PATH 当中,但是并不这么建议就是了!
好了,由于系统预设并不主动搜寻现在目录下的执行档,那么您应该怎样执行『现在目录下的执行档』呢?很简单呀!就是以相对路径的观念,由于『 .. 』是上层,而『 . 』是这一层,所以要执行这一层目录的命令就使用『 ./command 』即可!例如您的 /usr/local/squid/bin 底下执行 squid 则能够写成:
[test @tset bin]# ./squid <==以相对路径的观念来看!在本目录下达的指令写法!
请特别留意这方面的问题!『新手特别容易犯这个错误呢!』 命令重导向
基本上,这个子题是 bash 相当重要的观念,这里可得花点心思才行呦!
o 什么是『重导向, redirect ?』:简单的说,就是将您现在的所得资料转到其他地方去就是了!例如我们常用的,将现在的萤幕输出资料转到档案中去,就能够这么写:『ls -l / > test 』,那个大于的符号『 > 』就是将输出结果导向到 test 这个档案中的意思?!这个时候:
§ 假如您执行『 ls -l / 』而已的话,萤幕会将根目录的档案和目录都列出在萤幕上;
§ 但是当使用 > 导向到 test 这个档案中时,则萤幕不会显示任何讯息,但是会将刚刚您执行的结果输出到 test 这个档案中。
所以?,您只要『 vi test 』一下,就会知道 test 这个档案中记录了刚刚我们执行的资料结果?!但是,这里需要特别留意的是,当您使用 > 符号将资料由萤幕导向到档案中时,则:
§ 该档案(就是 test )若不存在,系统会自动的将他建立起来,但是,
§ 当这个档案存在的时候,那么系统就会先将这个档案内容清空,然后再将资料写入!
§ 也就是若以 > 输出到一个既存档案中,呵呵,那个档案就会被覆盖掉?!
除了这个 > 的符号之外,在 bash 命令执行的过程中,主要有三种输出入的状况,分别是:
1. 标准输入;代码为 0 ;或称为 stdin ;使用的方式为 <
2. 标准输出:代码为 1 ;或称为 stdout;使用的方式为 1>
3. 错误输出:代码为 2 ;或称为 stderr;使用的方式为 2>
注意了!那个 1> 和 2> 之间并没有空白字元!而相关的使用说明能够举例如下
[test @test test]# ls -al > list.txt <==将显示的结果输出到 list.txt 档案中,若该档案以存在则予以取代! [test @test test]# ls -al >> list.txt <==将显示的结果累加到 list.txt 档案中,该档案为累加的,旧资料保留! [test @test test]# ls -al 1> list.txt 2> list.err <==将显示的资料,正确的输出到 list.txt 错误的资料输出到 list.err [test @test test]# ls -al 1> list.txt 2>&1 <==将显示的资料,不论正确或错误均输出到 list.txt 当中! [test @test test]# ls -al 1> list.txt 2> /dev/null<==将显示的资料,正确的输出到 list.txt 错误的资料则予以丢弃!注意!错误和正确档案输出到同一个档案中,则必须以上面的方法来写!不能写成其他格式!
这个观念相当的重要,尤其是在 /etc/crontab 当中执行的时候,假如我们已知道错误的讯息为何,又不想要让错误的讯息一直填满 root 的信箱,就必须以 2> 搭配 /dev/null 这个垃圾桶黑洞装置,来将资料丢弃!这个相当的重要!
这里我们来说明一下命令重导向里面几个常用的符号和装置:
o < :由 < 的右边读入参数档案;
o > :将原本由萤幕输出的正确资料输出到 > 右边的 file ( 档案名称 ) 或 device ( 装置,如 printer )去;
o >> :将原本由萤幕输出的正确资料输出到 >> 右边,和 > 不同的是,该档案将不会被覆盖,而新的资料将以『增加的方式』增加到该档案的最后面;
o 2> :将原本应该由萤幕输出的错误资料输出到 2> 的右边去。
o /dev/null :能够说成是黑洞装置!
好了,对于『 > , >> 』这两个东西有一定的概念之后,我们来深入的谈一谈『命令输出重导向』的观念吧!如前所述,基本上, Linux 执行的结果中,能够约略的分成『正确输出』和『错误输出』两种方式。例如,当您以一般身份执行 find 这个指令时,例如执行『 find / -name testing 』时,由于您是一般身份,又有些资料夹是不允许一般身份者进入的,所以?,当您使用 find 时,就会有错误讯息发生了!但同时假如有 testing 这个档案在您能够进入的资料夹当中,那么萤幕也会输出到给您看!因此,就具备正确的和错误的输出两种?!(分别称为 Stdout 和 Stderror)例如下面为执行结果:里面的『 find: /home/root: Permission denied 』就告诉您该资料夹您没有权限进入,这就是错误的输出了,那么『 /home/test/tseting 』就是正确的输出了!
[test @test test]# find / -name testing find: /home/test1: Permission denied <==这是错误的输出 find: /home/root: Permission denied <==这是错误的输出 find: /home/masda: Permission denied <==这是错误的输出 /home/test/testing<==这是『正确』的输出 [test @test test]#
好了,那么假如我们想要将资料输出到 list 这个档案中呢?执行『 find / -name testing > list 』会有什么结果?呵呵,您会发现 list 里面存了刚刚那个『正确』的输出资料,至于萤幕上还是会有错误的讯息出现呢!伤脑筋!假如想要将正确的和错误的资料分别存入不同的档案中需要怎么做?!呵呵!其实在资料的重导向方面,正确的写法应该是『 1> 』和『 2> 』才对!但是假如只有 > 则预设是以 1> 来进行资料的!那个 1> 是输出正确资料, 2> 则是错误资料输出项目。也就是说:
? 1> :是将正确的资料输出到指定的地方去
? 2> :是将错误的资料输出到指定的地方去
好了,那么上面的例子中,我们怎样将资料输出到不同的地方去呢?能够这么写:
[test @test test]# find / -name testing 1> list_right 2> list_error
这样一来,刚刚执行的结果中,有 Permission 的那几行错误资讯都会跑到 list_error 这个档案中,至于正确的输出资料则会存到 list_right 这个档案中?!这样能够了解了吗?假如有点混乱的话,去休息一下再来看看吧!!
再来,假如我只要正确的资料,错误的资讯我不要了呢?呵呵,这个时候 /dev/null 这个垃圾桶就很重要了!/dev/null 是什么呢?基本上,那就有点像是个『黑洞』的垃圾桶功能!当您输入的任何东西导向到这个虚拟的垃圾桶装置时,『他就会凭空消失不见了~~』,这个东西有用的很!例如上面的例子中,我们能够这么做,来将错误的资讯丢掉!
[test @test test]# find / -name testing 1> list_right 2> /dev/null
很神奇呦! error message 就会『不见了!』呵呵!真高兴!另外,假如我要将资料都写到同一个档案中呢?这个时候写法需要用到特别写法,请注意底下的写法呦!
[test @test test]# find / -name testing 1> list 2> list <==错误写法 [test @test tset]# find / -name testing 1> list 2>&1 <==正确写法
请特别留意这一点呢!同时写入同一个档案需要使用 2>&1 才对呦!
OK!了解了 >, 2>, >> 和 /dev/null 之后,那么那个 < 又是什么呀!?呵呵!以最简单的说法来说,那就是『将原本需要由键盘输入的资料,经由档案来读入』的意思,最明显的例子就是 mail 这个东西了!我们以 root 的身份来寄信给 root 好了,能够这样做:
1. 完全由键盘输入资料: [root @test test]# mail -s "test" root <== -s 表示标题, root 为收件者 I am root! <==以下的资料都是由键盘输入的 That’s OK . <==要结束键盘的输入时,需要在一行的最前面加上 . 即可! CC. <==是否需要有密件副本?无需的话,直接按下 Enter ! EOF <==表示送出的提示字元而已! 2. 由档案代替输入 [test @test tset]# mail -s "test" root < /root/.bashrc <==将 .bashrc 内容寄给 root !
很有趣吧! ^_^ 这样就能够将信寄出去?!所以说,熟悉命令重导像的话,对您可是相当的有帮助的呦!
好了,那么为何要使用命令输出重导向呢?这个问题一定会困扰您一下下的,假如您从来都没有写过 script 的话!好了,我们来说一说吧!
o 当萤幕输出的资讯很重要,而且我们需要将他存下来的时候;
o 背景执行中的程式,不希望他干扰萤幕正常的输出结果时;
o 一些系统的例行命令(例如写在 /etc/crontab 中的档案)的执行结果,希望他能够存下来时;
o 一些执行命令,我们已知道他可能的错误讯息,所以想以『 2> /dev/null 』将他丢掉时;
o 错误讯息和正确讯息需要分别输出时。
当然更有很多很多的功能的,最简单的就是网友们常常问到的:『为何我的 root 都会收到系统 crontab 寄来的错误讯息呢』这个咚咚是常见的错误,而假如我们已知道这个错误讯息是能够忽略的时候,嗯!『 2> errorfile 』这个功能就很重要了吧!了解了吗??
管线命令 ( pipe )
? 管线命令:
就如同前面所说的, bash 命令执行的时候有输出的资料会出现!那么假如这群资料必需要经过几道手续之后才能得到我们所想要的格式,应该怎样来设定?这就牵涉到管线命令的问题了( pipe ),管线命令使用的是『 | 』这个界定符号!另外,管线命令和『连续下达命令』是不相同的呦!这点底下我们会再说明。底下我们先举一个例子来说明一下简单的管线命令。
假设我们要读取 last 这个指令中,那个 root 登入的『次数』应该怎么作?注意呦!我们只需要『次数』。那么我所进行的步骤是:
1. 执行 last ,将任何这个月的任何人登入资料取出来;
2. 使用 grep 将上面的输出资料(stdout)当中的 root 撷取出来,其他的不要;
3. 使用 wc 这个能够计算行数的指令将上一步的资料计算行数!
由于 last 的输出是一行代表一次登入,所以只要计算几行就代表登入几次的意思,所以?!经由上面三个步骤,将 last 资料逐步的筛选,就能够得到我们的资料了!整个命令能够写成如下:
[test @test bin]# last [test @test bin]# last | grep root [test @test bin]# last | grep root | wc -l
您能够分别执行『 last 』然后再逐步增加为『 last | grep root 』,最后到上面那一行,那么就马上能够清楚的知道为何会这么做?!
底下我们来谈一谈一些基本的管线命令指令介绍:
? cut
语法:
[root @test /root ]# cut -d "分隔字元" [-cf] fields 参数说明: -d :后面接的是用来分隔的字元,预设是『空白字元』 -c :后面接的是『第几个字元』 -f :后面接的是第几个区块? 范例: [root @test /root]# cat /etc/passwd | cut -d ":" -f 1 <==将 passwd 这个档案里面,每一行里头的 : 用来作为分隔号, 而列出第一个区块!也就是姓名所在啦! [root @test /root]# last | cut -d " " -f1 <==以空白字元为分隔,并列出第一个区间! [root @test /root]# last | cut -c1-20<==将 last 之后的资料,每一行的 1-20 个字元取出来!
? 说明:
这个 cut 实在很好用!但是,说真的,除非您常常在分析 log 档案,否则使用到 cut 的机会并不多!好了! cut 主要的用途在于将『同一行里面的资料进行分解!』,最常使用在分析一些数据或文字资料的时候!这是因为有时候我们会以某些字元当作分割的参数,然后来将资料加以切割,以取得我们所需要的资料。我也很常使用这个功能呢!尤其是在分析 log 档案的时候,跟 awk 也是很常用的!
? sort
语法:
[root @test /root ]# sort [-t 分隔符号] [(+起始)(-结束)] [-nru] 参数说明: -t 分隔符号:使用分隔符号来隔开不同区间,预设是 tab +start -end:由第 start 区间排序到 end 区间 -n:使用『纯数字』排序(否则就会以文字型态来排序) -r :反向排序 -u :相同出现的一行,只列出一次! 范例: [root @test /root]# cat /etc/passwd | sort <==将列出来的个人帐号排序! [root @test /root]# cat /etc/passwd | sort -t: +2n <==将个人帐号中,以使用者 ID 来排序(以 : 来分隔,第三个为 ID ,但第一个代号为 0 之故) [root @test /root]# cat /etc/passwd | sort -t: +2nr <==反相排序?!
? 说明:
sort 同样是很常用的指令呢!因为我们常常需要比较一些资讯啦!举个上面的第二个例子来说好了!今天假设您有很多的帐号,而且您想要知道最大的使用者 ID 现在到哪一号了!呵呵!使用 sort 一下子就能够知道答案咯!当然其使用还不止此啦!有空的话不妨玩一玩!
? wc
语法:
[root @test /root ]# wc [-lmw] 参数说明: -l :多少行 -m :多少字元 -w :多少字? 范例: [root @test /root]# cat /etc/passwd | wc -l <==这个档案里头有多少行? [root @test /root]# cat /etc/passwd | wc -w <==这个档案里头有多少字!?
? 说明:
wc 也能够当作指令?呵呵!这可不是上洗手间的 WC 呢!这是相当有用的计算档案内容的一个工具组喔!举个例子来说,当您要知道现在您的帐号档案中有多少个帐号时,就使用上面的 wc -l 啦!因为 /etc/passwd 里头一行代表一个使用者呀!所以知道行数就晓得有多少的帐号在里头了!而假如要计算一个档案里头有多少个字元时,呵呵!就使用 wc -w 这个参数吧!
o uniq
语法:
[root @test /root ]# uniq 参数说明: 范例: [root @test /root]# last | cut -d" " -f1 | sort | uniq
o 说明:
这个指令用来将『重复的行删除掉只显示一个』,举个例子来说,您要知道这个月份登入您主机的使用者有谁,而不在乎他的登入次数,那么就使用上面的范例, (1)先将任何的资料列出;(2)再将人名单独出来;(3)经过排序;(4)只显示一个!由于这个指令是在将重复的东西减少,所以当然需要『配合排序过的档案』来处理?!例如我们侦测 Nimda 病毒的时候会用到的这个小指令即是!基本上,这个小程式能够让大家很清楚的知道命令重导向和管线处理的用途?!
o tee
语法:
[root @test /root ]# last | tee last.list | cut -d " " -f1 参数说明: 范例: [root @test /root]# last | tee last.list | cut -d " " -f1
o 说明:
有没有发现在命令重导向的时候,假如我们要将资料送出到档案的时候,萤幕上就不会出现任何的资料!那么假如我们需要将资料同时显示在萤幕上跟档案中呢?呵呵!这个时候就需要 tee 这个指令?!使用 last 能够查看到这个月份的登入资料,而使用了 tee 之后,会将资料同时传给下一个命令去执行,也会将资料写入 last.list 这个档案中!也是个好帮手!
o tr
语法:
[root @test /root ]# tr [-ds] SET1 参数说明: -d :删除 SET1 这个字串 -s :取代掉重复的字元! 范例: [root @test /root]# last | tr ’[a-z]’ ’[A-Z]’ <==将小写改成大写 [root @test /root]# cat /etc/passwd | tr -d : <==嘿嘿! : 这个符号在 /etc/passwd 中不见了! [root @test /root]# cat /home/test/dostxt | tr -d ’\r’ > dostxt-noM <==将 DOS 档案的字尾符号 ^M 的符号去除!
o 说明:
其实这个指令也能够写在『正规表示法』里头!因为他也是由正规表示法的方式来取代资料的!以上面的例子来说,使用 [] 能够设定一串字呢!也常常用来取代档案中的怪异符号!例如上面第三个例子当中,能够去除 DOS 档案留下来的 ^M 这个断行的符号!这东西相当的有用!相信处理 Linux & Windows 系统中的人们最麻烦的一件事就是这个事情啦!亦即是 DOS 底下会自动的在美行行尾加入 ^M 这个断行符号!这个时候我们能够使用这个 tr 来将 ^M 去除! ^M 能够使用 \r 来代替之!
o split
语法:
[root @test /root ]# split [-bl] 输入档案 输出档案前导字元 参数说明: -b :以档案 size 来分 -l :以行数来分 范例: [root @test /root]# split -l 5 /etc/passwd test <==会产生 testaa, testab, testac... 等等的档案
o 说明:
在 Windows 的情况下,您要将档案分割需要怎样作?!伤脑筋吧!呵呵!在 Linux 底下就简单的多了!您要将档案分割的话,那么就使用 -b size 来将一个分割的档案限制其大小,假如是行数的话,那么就使用 -l line 来分割!好用的很!如此一来,您就能够轻易的将您的档案分割成 floppy 的大小,方便您 copy ?!
管线命令在 bash 的连续的处理程式中是相当重要的!另外,在 log file 的分析当中也是相当重要的一环,所以请特别留意!好嘛!?
? 连续命令:
咦!连续命令和管线命令有什么不相同?!基本上,连续命令能够想成是 shell script 写在 command mode (指令命令列模式)的一种方式!和刚刚的管线命令将输出资料持续的进行处理的方式是不相同的!因为『在管线命令中,每个指令所使用的资料都是相关的;但是在连续命令的情况下,每个指令的输出和输入都是单独的』。举例来说,我在指令列底下,要将 mount CD-ROM 的模组一起挂上来,能够这样写:
[root @tset /root]# modprobe cdrom ; modprobe ide-cd
? 两个指令之间以『 ; 』符号来作为界定!则相当于输入了 modprobe cdrom ,并且执行完毕之后,再执行 modprobe ide-cd 的意思!两的命令之间并没有绝对的相关性!
|