Chinaunix首页 | 论坛 | 博客
  • 博客访问: 25806
  • 博文数量: 14
  • 博客积分: 2000
  • 博客等级: 大尉
  • 技术积分: 115
  • 用 户 组: 普通用户
  • 注册时间: 2009-05-24 13:36
文章分类

全部博文(14)

文章存档

2011年(1)

2009年(13)

我的朋友

分类: LINUX

2009-06-20 10:32:47

认识bash shell
**type:查看指令是外部命令还是内建在bash当中的。
[root@linux ~]# type [-tpa] name
参数∶
    ∶不加任何参数时,则 type 会显示出那个 name 是外部指令还是 bash 内建的指令!
-t  ∶当加入 -t 参数时,type 会将 name 以底下这些字眼显示出他的意义∶
      file    ∶表示为外部指令;
      alias   ∶表示该指令为命令别名所设定的名称;
      builtin ∶表示该指令为 bash 内建的指令功能;
-p  ∶如果后面接的 name 为指令时,会显示完整档名(外部指令)或显示为内建指令;
-a  ∶会将由 PATH 变数定义的路径中,将所有含有 name 的指令都列出来,包含 alias
范例∶
范例一∶查询一下 ls 这个指令是否为 bash 内建?
[root@linux ~]# type ls
ls is aliased to `ls --color=tty'
# 没有加上任何参数,仅列出 ls 这个指令的最主要使用情况
[root@linux ~]# type -t ls
alias
# -t 参数则仅列出 ls 这个指令的最主要使用情况说明
[root@linux ~]# type -a ls
ls is aliased to `ls --color=tty'
ls is /bin/ls
# 利用所有方法找出来的 ls 相关资讯都会被列出来!

范例二∶那么 cd 呢?
[root@linux ~]# type cd
cd is a shell builtin
这个 type 也可以用来作为类似 which 指令的用途啦!找指令用的!


**bash中定义变量应该注意的要点:
   1. 变量与变量内容以等号『=』来连结;
   2. 等号两边不能直接接空白字元;
   3. 变量名称只能是英文字母与数字,但是数字不能是开头字元,和C++标识符类似;
   4. 若有空白字元可以使用双引号『 " 』或单引号『 ' 』来将变量内容结合起来,但须要特别留意,
      双引号内的特殊字元可以保有变量特性,但是单引号内的特殊字元则仅为一般字元;
   5. 必要时需要以转义字符『 \ 』来将特殊符号 ( 如 Enter, $, \, 空白字元, ' 等 ) 变成一般符号;
   6. 在一串指令中,还需要藉由其他的指令提供的资讯,可以使用 quote 『 ` command` 』;(特别
      特别注意,那个 ` 是键盘上方的数字键 1 左边那个按键,而不是单引号!)
   7. 若该变量为扩增变量内容时,则需以双引号及 $变量名称 如∶『 "$PATH":/home』继续累加内容;
   8. 若该变量需要在其他子程序执行,则需要以 export 来使变量变成环境变量, 如『export PATH』;
   9. 通常大写字元为系统预设变量,自行设定变量可以使用小写字元,方便判断 ( 纯粹依照使用者兴趣与嗜好 ) ;
  10. 取消变量的方法为∶『unset 变量名称』。
范例一∶设定一变数 name ,且内容为 VBird 。
[root@linux ~]# 12name=VBird
-bash: 12name=VBird: command not found  <==萤幕会显示错误!因为不能以数字开头!
[root@linux ~]# name = VBird  <==还是错误!因为有空白!
[root@linux ~]# name=VBird    <==OK 的啦!

范例二∶承上题,若变数内容为 VBird's name 呢?
[root@linux ~]# name=VBird's name  
# 因为单引号可以将 Enter 这个特殊字符取消,所以,您可以继续在下一行输入内容~
# 不过,这与我们要达到的功能不同,所以,算是失败的啦!
[root@linux ~]# name="VBird's name"  <==OK 的啦!
[root@linux ~]# name=VBird\'s\ name
# 利用反斜线 (\) 跳脱特殊字元,例如单引号与空白键,这也是 OK 的啦!

范例三∶我要在 PATH 这个变数当中『累加』:/home/dmtsai/bin 这个目录
[root@linux ~]# PATH=$PATH:/home/dmtsai/bin
[root@linux ~]# PATH="$PATH":/home/dmtsai/bin
# 上面这两种格式在 PATH 里头的设定都是 OK 的!但是底下的例子就不见得棉!

范例四∶呈范例三,我要将 name 的内容多出 "yes" 呢?
[root@linux ~]# name=$nameyes  
# 知道了吧?如果没有双引号,那么变数成了啥?name 的内容是 $nameyes 这个变数!
# 呵呵!我们可没有设定过 nameyes 这个变数呐!所以,应该是底下这样才对!
[root@linux ~]# name="$name"yes
[root@linux ~]# name=${name}yes

范例五∶如何让我刚刚设定的 name=VBird 可以用在下个 shell 的程序?
[root@linux ~]# name=VBird
[root@linux ~]# bash        <==进入到所谓的子程序
[root@linux ~]# echo $name  <==嘿嘿!并没有刚刚设定的内容喔!
[root@linux ~]# exit        <==离开刚刚的子程序
[root@linux ~]# export name
[root@linux ~]# bash        <==进入到所谓的子程序
[root@linux ~]# echo $name  <==出现了设定值了!
[root@linux ~]# exit        <==离开刚刚的子程序
# 什么是『子程序』呢?就是说,在我目前这个 shell 的情况下,
# 去启用另一个新的 shell ,新的那个 shell 就是子程序啦!在一般的状态下,
# 父程序的自订变数是无法在子程序内使用的。但是透过 export 将变数变成
# 环境变数后,就能够在子程序底下应用了!很不赖吧!至于程序的相关概念,
# 我们会在『程序与资源管理』章节当中提到的喔!

范例六∶如何进入到您目前核心的模组目录?
[root@linux ~]# cd /lib/modules/`uname -r`/kernel
# 每个作业系统核心版本都不相同,以 FC4 为例,他的预设核心版本是
# 2.6.11-1.1369_FC4 所以,他的模组目录在 /lib/modules/2.6.11-1.1369_FC4/kernel 。
# 因为每个 distributions 的这个值都不相同,但是我们却可以利用 uname -r 这个指令
# 先取得版本资讯,所以棉,就可以透过上面指令当中的内含指令 `uname -r`
# 先取得版本输出到 cd .. 那个指令当中,就能够顺利的进入目前核心的驱动程式所放置
# 的目录棉!很方便吧!

范例七∶取消刚刚设定的 name 这个变数内容
[root@linux ~]# unset name


**系统的一些环境变量:查看系统的环境变量可以使用env、set或export命令:
# HOME ∶ 代表使用者的家目录。还记得我们可以使用 cd ~ 去到使用者的家目录吗?或者利用
    cd 就可以直接回到使用者家目录了。那就是取用这个功能啦~ 有很多程式都可能会取用到这
   个变数的值喔!

# SHELL ∶ 告知我们,目前这个环境使用的 SHELL 是哪支程式? 如果是 bash 的话,预设是
    /bin/bash 的啦!

# HISTSIZE ∶ 这个与『历史命令』有关,亦即是, 我们曾经下达过的指令可以被系统记录下来,
   而记录的『笔数』则是由这个值来设定的。

# ENV ∶ 这个使用者所使用的个人化环境设定档的读取档案。

# MAIL ∶ 当我们使用 mail 这个指令在收信时,系统会去读取的邮件信箱档案 (mailbox)。

# PATH ∶ 就是执行档搜寻的路径啦~目录与目录中间以冒号(:)分隔, 由于档案的搜寻是依序由
   PATH 的变数内的目录来查询,所以,目录的顺序也是重要的喔。

# LANG ∶ 这个重要!就是语系档案棉~很多资料都会用到他, 举例来说,当我们在启动某些
   perl 的程式语言档案时,他会主动的去分析语系资料档案, 如果发现有他无法解析的编码语
  系,可能会产生错误喔!一般来说,我们中文编码通常是 zh_TW.Big5 或者是 zh_TW.UTF-8,
  这两个编码偏偏不容易被解译出来,所以,有的时候,可能需要修订一下语系资料。

# RANDOM ∶ 这个玩意儿就是『随机乱数』的变数啦!目前大多数的 distributions 都会有乱数
  产生器,那就是 /dev/random 这个档案。 我们可以透过这个乱数档案相关的变数 ($RANDOM)
  来随机取得乱数值喔。在 BASH 的环境下,这个 RANDOM 变数的内容,介于 0~32767 之间,
  所以,你只要 echo $RANDOM 时,系统就会主动的随机取出一个介于 0~32767 的数值。万一
  我想要使用 0~9 之间的数值呢?呵呵~利用 declare 宣告数值类型, 然后这样做就可以了∶
  [root@linux ~]# declare -i number=$RANDOM*10/32767 ; echo $number

# PS1:这个东西就是我们的『命令提示字元』啊!
预设的 bash 的 PS1 变数内的特殊符号代表意义∶
# \d ∶代表日期,格式为 Weekday Month Date,例如 "Mon Aug 1"
# \H ∶完整的主机名称。举例来说,鸟哥的练习机 linux.dmtsai.tw ,那么这个主机名称就是 linux.dmtsai.tw
# \h ∶仅取主机名称的第一个名字。以上述来讲,就是 linux 而已, .dmtsai.tw 被省略。
# \t ∶显示时间,为 24 小时格式,如∶ HH:MM:SS
# \T ∶显示时间,12 小时的时间格式!
# \A ∶显示时间,24 小时格式, HH:MM
# \u ∶目前使用者的帐号名称;
# \v ∶BASH 的版本资讯;
# \w ∶完整的工作目录名称。家目录会以 ~ 取代;
# \W ∶利用 basename 取得工作目录名称,所以仅会列出最后一个目录名。
# \# ∶下达的第几个指令。
# \$ ∶提示字元,如果是 root 时,提示字元为 # ,否则就是 $
由预设的 PS1 内容为∶ '\[\u@\h \W\]\$ ' 就可以了解为何我们的提示字元会是∶ [root@linux ~]#
了吧!好了,那么假设我想要有类似底下的提示字元∶
      [root@linux /home/dmtsai 16:50 #12]#
,那个 # 代表第 12 次下达的指令。 那么应该如何设定 PS1 呢?可以这样啊∶
[root@linux home]# PS1='[\u@\h \w \A #\#]\$ '

# $∶(关于本 shell 的 PID)
想要知道我们的 shell 的 PID ,就可以∶ echo $$ 即可!

# ?∶(关于上个执行指令的回传码)
也就是上一个命令的main函数的返回值,哈哈。

把自定义的变量转换为环境变量使用命令:export 变量

系统语系档案的变量
查看系统所支援的语系可以使用命令:locale -a
修改语系编码可以修改以下环境变量:
[root@linux ~]# LANG         <==主语言的环境
[root@linux ~]# LC_CTYPE     <==字元辨识的编码
[root@linux ~]# LC_NUMERIC   <==数字系统的显示讯息
[root@linux ~]# LC_TIME      <==时间系统的显示资料
[root@linux ~]# LC_COLLATE   <==字串的比较与排序等
[root@linux ~]# LC_MONETARY  <==币值格式的显示等
[root@linux ~]# LC_MESSAGES  <==讯息显示的内容,如功能表、错误讯息等
[root@linux ~]# LC_ALL       <==语言环境的整体设定。
注意:一般在tty1~tty6终端界面是无法显示像中文这么复杂的编码文字的。
修改系统的语系编码可以修改/etc/sysconfig/i18n这个文件:
[root@linux ~]# vi /etc/sysconfig/i18n
LANG="en_US.UTF-8"
SYSFONT="latarcyrheb-sun16"
SUPPORTED="zh_TW.UTF-8:zh_TW:zh:en_US.UTF-8"

变量的有效范围:
我们自己定义的变量,只在当前的shell环境中有效,在子程序中不会存在。只有当我们使用
“export 变量”把命令变为环境变量以后,子程序才能使用这个变量。可以用下面的方法来
理解:
    *  当启动一个 shell ,作业系统分配一记忆区块给 shell 使用,此区域之变量可以让
       子程序存取,也就是保存环境变量的区域;
    * 利用 export 功能,可以让变量的内容写到上述的记忆区块当中(环境变量);
    * 当载入另一个 shell 时 (亦即启动子程序,而离开原本的父程序了),子 shell 可以
      将父 shell 的环境变量所在的记忆区块导入自己的环境变量区块当中。

变量的键盘读取:
要读取来自键盘输入的变量,可以使用命令:read
[root@linux ~]# read [-pt] variable
参数∶
-p  ∶后面可以接提示字元!
-t  ∶后面可以接等待的『秒数!』这个比较有趣~不会一直等待使用者啦!
范例∶
范例一∶让使用者由键盘输入一内容,将该内容变成 atest 变数
[root@linux ~]# read atest
This is a test
[root@linux ~]# echo $atest
This is a test
范例二∶提示使用者 30 秒内输入自己的大名,将该输入字串做成 named 变数
[root@linux ~]# read -p "Please keyin your name: " -t 30 named
Please keyin your name: VBird Tsai
[root@linux ~]# echo $named
VBird Tsai

变量的申明:
申明一个变量以及它的属性可以书用命令:declare / typeset
[root@linux ~]# declare [-aixr] variable
参数∶
-a  ∶将后面的 variable 定义成为阵列 (array)
-i  ∶将后面接的 variable 定义成为整数数字 (integer)
-x  ∶用法与 export 一样,就是将后面的 variable 变成环境变量;
-r  ∶将一个 variable 的变数设定成为 readonly ,该变数不可被更改内容,也不能 unset
范例∶
范例一∶让变数 sum 进行 100+300+50 的加总结果
[root@linux ~]# sum=100+300+50
[root@linux ~]# echo $sum
100+300+50  <==咦!怎么没有帮我计算加总?因为这是文字型态的变量属性啊!
[root@linux ~]# declare -i sum=100+300+50
[root@linux ~]# echo $sum
450         <==了乎??
范例二∶将 sum 变成环境变量
[root@linux ~]# declare -x sum
范例三∶让 sum 变成唯读属性,不可更动!
[root@linux ~]# declare -r sum
[root@linux ~]# sum=tesgting
-bash: sum: readonly variable  <==老天爷~不能改这个变量了!

变量数组:
数组的设定方式是:var[index]=content
范例∶设定 var[1] ~ var[3] 的变数。
[root@linux ~]# var[1]="small min"
[root@linux ~]# var[2]="big min"
[root@linux ~]# var[3]="nice min"
[root@linux ~]# echo "${var[1]}, ${var[2]}, ${var[3]}"

与档案系统及程序的限制关系∶ ulimit
[root@linux ~]# ulimit [-SHacdflmnpstuv] [配额]
参数∶
-H  ∶hard limit ,严格的设定,必定不能超过设定的值;
-S  ∶soft limit ,警告的设定,可以超过这个设定值,但是会有警告讯息,
      并且,还是无法超过 hard limit 的喔!也就是说,假设我的 soft limit
      为 80 , hard limit 为 100 ,那么我的某个资源可以用到 90 ,
      可以超过 80 ,还是无法超过 100 ,而且在 80~90 之间,会有警告讯息的意思。
-a  ∶列出所有的限制额度;
-c  ∶可建立的最大核心档案容量 (core files)
-d  ∶程序资料可使用的最大容量
-f  ∶此 shell 可以建立的最大档案容量 (一般可能设定为 2GB)单位为 Kbytes
-l  ∶可用于锁定 (lock) 的记忆体量
-p  ∶可用以管线处理 (pipe) 的数量
-t  ∶可使用的最大 CPU 时间 (单位为秒)
-u  ∶单一使用者可以使用的最大程序(process)数量。
范例∶
范例一∶列出所有的限制资料
[root@linux ~]# ulimit -a
范例二∶限制使用者仅能建立 1MBytes 以下的容量的档案
[root@linux ~]# ulimit -f 1024
注意:ulimit -f的单位是Kbytes。
另外一般身份的使用者如果以ulimit -f设定了最大文件容量以后,那么他以后只能减小
这个最大容量的大小而不能增加他的大小。

变量的额外设定功能:
1. 完整呈现 vbird 这个变量的内容;
[root@linux ~]# vbird="/home/vbird/testing/testing.x.sh"
[root@linux ~]# echo ${vbird}
/home/vbird/testing/testing.x.sh
2. 在 vbird 变量中,从最前面开始比对,若开头为 / ,则删除两个 /
   之间的所有资料,亦即 /*/
[root@linux ~]# echo ${vbird##/*/}
testing.x.sh    <==删除了 /home/vbird/testing/
[root@linux ~]# echo ${vbird#/*/}
vbird/testing/testing.x.sh   <==仅删除 /home/ 而已
# 这两个小例子有趣了~变数名称后面如果接了两个 ## ,表示在 ##
# 后面的字串取『最长的』那一段;如果仅有一个 # ,表示取『最小的那一段』喔!
3. 承上题,如果是从后面开始,删除 /* 呢?
[root@linux ~]# echo ${vbird%%/*/}
/home/vbird/testing/testing.x.sh  <==都没被删除
[root@linux ~]# echo ${vbird%%/*}
    <==被删除光了!
[root@linux ~]# echo ${vbird%/*}
/home/vbird/testing   <==只删除 /testing.x.sh 部分
# 这个例子当中需要特别注意,那个 % 比对的是『最后面那个字元』的意思,
# 所以棉,第一个方式当然不对~因为 vbird 这个变数的内容最后面是 h 而不是 / 啊!
# 至于 %%/* 则是删除『最长的那个 /* 』,当然就是全部喔!而 %/* 则是最短的那个!
4. 将 vbird 变量中的 testing 取代为 TEST
[root@linux ~]# echo ${vbird/testing/TEST}
/home/vbird/TEST/testing.x.sh
[root@linux ~]# echo ${vbird//testing/TEST}
/home/vbird/TEST/TEST.x.sh
# 如果变量后面接的是 / 时,那么表示后面是进行『取代』的工作~而且仅取代『第一个』
# 但如果是 // ,则表示全部的字串都取代啊!

命令别名与历史命令:
取命令别名:alias 别名='指令 参数'
例如:alias lm='ls -l | more'
取消别名:alias lm
查看当前使用了那些别名:alias
历史命令:history
[root@linux ~]# history [n]
[root@linux ~]# history [-c]
[root@linux ~]# history [-raw] histfiles
参数∶
n   ∶数字,意思是『要列出最近的 n 笔命令列表』!
-c  ∶将目前的 shell 中的所有 history 内容全部消除
-a  ∶将目前新增的 history 指令新增入 histfiles 中,若没有加 histfiles ,
      则预设写入 ~/.bash_history
-r  ∶将 histfiles 的内容读到目前这个 shell 的 history 记忆中;
-w  ∶将目前的 history 记忆内容写入 histfiles 中!
范例∶
范例一∶列出目前记忆体内的所有 history 记忆
[root@linux ~]# history
# 前面省略
 1017  man bash
 1018  ll
 1019  history
 1020  history
# 列出的资讯当中,共分两栏,第一栏为该指令在这个 shell 当中的代码,
# 另一个则是指令本身的内容喔!至于会秀出几笔指令记录,则与 HISTSIZE 有关!
范例二∶列出目前最近的 3 笔资料
[root@linux ~]# history 3
 1019  history
 1020  history
 1021  history 3
范例三∶立刻将目前的资料写入 histfile 当中
[root@linux ~]# history -w
# 在预设的情况下,会将历史纪录写入 ~/.bash_history 当中!
[root@linux ~]# echo $HISTSIZE
1000
查到历史命令,我们还可以使用以下功能来帮助我们执行命令:
[root@linux ~]# !number
[root@linux ~]# !command
[root@linux ~]# !!
参数∶
number  ∶执行第几笔指令的意思;
command ∶由最近的指令向前搜寻『指令串开头为 command』的那个指令,并执行;
!!      ∶就是执行上一个指令(相当于按↑按键后,按 Enter)
范例∶
[root@linux ~]# history
   66  man rm
   67  alias
   68  man history
   69  history
[root@linux ~]# !66  <==执行第 66 笔指令
[root@linux ~]# !!   <==执行上一个指令,本例中亦即 !66
[root@linux ~]# !al  <==执行最近以 al 为开头的指令(上头列出的第 67 个)

登录信息显示资料:
我们从终端机tty1~tty6登入的时候,会显示的几行提示字符串,这些提示字符串便是在
/etc/issue这个文件里面设定的:
[root@linux ~]# cat /etc/issue
Fedora Core release 4 (Stentz)
Kernel \r on an \m
\r及\m是啥?下面便来介绍issue內的个代码的意义:
\d 本地端时间的日期;
\l 显示第几个终端机介面;
\m 显示硬体的等级 (i386/i486/i586/i686...);
\n 显示主机的网路名称;
\o 显示 domain name;
\r 作业系统的版本 (相当于 uname -r)
\t 显示本地端时间的时间;
\s 作业系统的名称;
\v 作业系统的版本。
当用户通过ssh或telnet远程登录系统的时候,登入界面会显示/etc/issue.net的内容。
如果我们想让一些讯息被tty和远程登录的用户都看到,可以把信息加入到/etc/motd里面:
[root@linux ~]# vi /etc/motd
Hello everyone,
Our server will be maintained at 2005/10/10 0:00 ~ 24:00.
Please don't login at that time. ^_^

那么当你的使用者登入主机后,就会显示这样的讯息出来∶

Last login: Mon Aug 15 10:17:10 2005 from 127.0.0.1
Hello everyone,
Our server will be maintained at 2005/10/10 0:00 ~ 24:00.
Please don't login at that time. ^_^

环境设定档:
系统设定值:
# /etc/sysconfig/i18n: 设定系统的语言编码,前面已经介绍过了。
# /etc/profile: 这个档案设定了几个重要的变数,例如∶『PATH、USER、MAIL、 HOSTNAME、
HISTSIZE、umask』等等,也同时规划出 /etc/inputrc 这个针对键盘热建设定的档案的资料内容。
# /etc/bashrc: 这个档案在规划 umask 的功能,也同时规划出提示字元的内容 (就是里头那个 PS1 啦!)
/etc/man.config: 这个档案规定了下达 man 的时候,该去哪里查看资料的路径设定!们搜寻 man page
时,会依据 MANPATH 的路径去分别搜寻啊!
个人设定值:
~/.bash_profile, ~/.bash_login, ~/.profile:
这三个档案通常只要一个就够了,一般预设是以 ~/.bash_profile 的档名存在。
这个档案可以定义个人化的路径 (PATH) 与环境变量等等。不过,还是有顺位上的差异, bash 启动时,
会先去读取 ~/.bash_profile,找不到时,就去读取 ~/.bash_login ,然后才是 ~/.profile。
~/.bashrc:
设定个人化的命令别名、路径、自定义的环境变量等等。
~/.bash_history:
记录历史命令的文件,而这个档案能够记录几笔资料,则与 HISTSIZE 这个变数有关啊。每次登入 bash
后,bash 会先读取这个档案,将所有的历史指令读入记忆体, 因此,当我们登入 bash 后就可以查知上
次使用过哪些指令棉。
~/.bash_logout:
这个档案则记录了『当我登出 bash 后,系统再帮我做完什么动作后才离开』的意思。预设的情况下,登出时,
bash 只是帮我们清掉萤幕的讯息而已。 不过,你也可以将一些备份或者是其他你认为重要的工作写在这个档
案中(例如清空暂存档), 那么当你离开 Linux 的时候,就可以解决一些烦人的事情!
在我们登入 bash 的时候,这些设定档到底是如何读取的呢?他是这样读取的∶
   1.  先读取 /etc/profile ,再根据 /etc/profile 的内容去读取其他额外的设定档, 例如 /etc/profile.d
      与 /etc/inputrc 等等设定档;
   2. 根据不同的使用者,到使用者家目录去读取 ~/.bash_profile 或 ~/.bash_login 或 ~/.profile 等设定档;
   3. 根据不同使用者,到他家目录去读取 ~/.bashrc 。
利用 source 或小数点 (.) 都可以将设定档的内容读进来目前的 shell 环境中! 举例来说,我修改了
 ~/.bashrc ,那么不需要登出,立即以 source ~/.bashrc 就可以将刚刚最新设定的内容读进来目前的环境中!

屏幕输出重定向:
   1. 标准输入(stdin) ∶代码为 0 ,使用 < 或 << ;
   2. 标准输出(stdout)∶代码为 1 ,使用 > 或 >> ;(>>是以追加方式输出到文件)
   3. 标准错误输出(stderr)∶代码为 2 ,使用 2> 或 2>> ;
重定向以后信息不会在屏幕显示,需要在屏幕上显示的同时输出到文件可以使用tee命令:
[root@linux ~]# tee [-a] file
参数∶
-a  ∶以累加 (append) 的方式,将资料加入 file 当中!
范例∶
[root@linux ~]# last | tee last.list | cut -d " " -f1
# 这个范例可以让我们将 last 的输出存一份到 last.list 档案中;
[root@linux ~]# ls -l /home | tee ~/homefile | more
# 这个范例则是将 ls 的资料存一份到 ~/homefile ,同时萤幕也有输出讯息!
[root@linux ~]# ls -l / | tee -a ~/homefile | more
# 要注意∶ tee 后接的档案会被覆盖,所以,我们要加上 -a
# 这个参数才能将讯息累加。


命令执行的判断依据∶ ; , &&, ||
;前一个命令执行完毕后执行下一个命令。
&&前一个命令执行成功(即$?=0)后再执行下一个命令。
||前一个命令执行错误时才会执行下一个命令。

撷取命令∶ cut, grep
[root@linux ~]# cut -d'分隔字元' -f fields
[root@linux ~]# cut -c 字元区间
参数∶
-d  ∶后面接分隔字元。与 -f 一起使用;
-f  ∶依据 -d 的分隔字元将一段讯息分割成为数段,用 -f 取出第几段的意思;
-c  ∶以字元 (characters) 的单位取出固定字元区间;
范例∶
范例一∶将 PATH 变数取出,我要找出第三个路径。
[root@linux ~]# echo $PATH
/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/X11R6/bin:/usr/games:
[root@linux ~]# echo $PATH | cut -d ':' -f 5
# 嘿嘿!如此一来,就会出现 /usr/local/bin 这个目录名称!
# 因为我们是以 : 作为分隔符号,第五个就是 /usr/local/bin 啊!
# 那么如果想要列出第 3 与第 5 呢?,就是这样∶
[root@linux ~]# echo $PATH | cut -d ':' -f 3,5
范例二∶将 export 输出的讯息,取得第 12 字元以后的所有字串
[root@linux ~]# export
declare -x HISTSIZE="1000"
declare -x INPUTRC="/etc/inputrc"
declare -x KDEDIR="/usr"
declare -x LANG="zh_TW.big5"
......其他省略......
[root@linux ~]# export | cut -c 12-
HISTSIZE="1000"
INPUTRC="/etc/inputrc"
KDEDIR="/usr"
LANG="zh_TW.big5"
......其他省略......
# 知道怎么回事了吧?用 -c 可以处理比较具有格式的输出资料!
# 我们还可以指定某个范围的值,例如第 12-20 的字元,就是 cut -c 12-20 等等!
范例三∶用 last 将这个月登入者的资讯中,仅留下使用者大名
[root@linux ~]# last
vbird  tty1  192.168.1.28   Mon Aug 15 11:55 - 17:48  (05:53)
vbird  tty1  192.168.1.28   Mon Aug 15 10:17 - 11:54  (01:37)
[root@linux ~]# last | cut -d ' ' -f 1
# 用 last 可以取得最近一个月登入主机的使用者资讯,
# 而我们可以利用空白字元的间隔,取出第一个资讯,就是使用者帐号棉!
# 但是因为 vbird tty1 之间空格有好几个,并非仅有一个,所以,如果要找出
# tty1 其实不能以 cut -d ' ' -f 1,2 喔!输出的结果会不是我们想要的。
grep:
[root@linux ~]# grep [-acinv] '搜寻字串' filename
参数∶
-a ∶将 binary 档案以 text 档案的方式搜寻资料
-c ∶计算找到 '搜寻字串' 的次数
-i ∶忽略大小写的不同,所以大小写视为相同
-n ∶顺便输出行号
-v ∶反向选择,亦即显示出没有 '搜寻字串' 内容的那一行!
范例∶
范例一∶将 last 当中,有出现 root 的那一行就取出来;
[root@linux ~]# last | grep 'root'
范例二∶与范例一相反,只要没有 root 的就取出!
[root@linux ~]# last | grep -v 'root'
范例三∶在 last 的输出讯息中,只要有 root 就取出,并且仅取第一栏
[root@linux ~]# last | grep 'root' |cut -d ' ' -f1
# 在取出 root 之后,利用上个指令 cut 的处理,就能够仅取得第一栏棉!

排序命令∶ sort, wc, uniq
sort排序的字符与语系的编码有关,因此, 如果您需要排序时,建议使用 LC_ALL=C 来让语系统一,
资料排序比较好一些。
[root@linux ~]# sort [-fbMnrtuk] [file or stdin]
参数∶
-f  ∶忽略大小写的差异,例如 A 与 a 视为编码相同;
-b  ∶忽略最前面的空白字元部分;
-M  ∶以月份的名字来排序,例如 JAN, DEC 等等的排序方法;
-n  ∶使用『纯数字』进行排序(预设是以文字型态来排序的);
-r  ∶反向排序;
-u  ∶就是 uniq ,相同的资料中,仅出现一行代表;
-t  ∶分隔符号,预设是 tab 键;
-k  ∶以那个区间 (field) 来进行排序的意思,
范例∶
范例一∶个人帐号都记录在 /etc/passwd 下,请将帐号进行排序。
[root@linux ~]# cat /etc/passwd | sort
adm:x:3:4:adm:/var/adm:/sbin/nologin
apache:x:48:48:Apache:/var/www:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
# 我省略很多的输出~由上面的资料看起来, sort 是预设『以第一个』资料来排序,
# 而且预设是以『文字』型态来排序的喔!所以由 a 开始排到最后棉!
范例二∶/etc/passwd 内容是以 : 来分隔的,我想以第三栏来排序,该如何?
[root@linux ~]# cat /etc/passwd | sort -t ':' -k 3
root:x:0:0:root:/root:/bin/bash
iiimd:x:100:101:IIIMF server:/usr/lib/iiim:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
# 看到特殊字体的输出部分了吧?怎么会这样排列啊?呵呵!没错啦~
# 如果是以文字型态来排序的话,原本就会是这样,想要使用数字排序∶
# cat /etc/passwd | sort -t ':' -k 3 -n
# 这样才行啊!用那个 -n 来告知 sort 以数字来排序啊!
范例三∶利用 last ,将输出的资料仅取帐号,并加以排序
[root@linux ~]# last | cut -d ' ' -f1 | sort
uniq:相同的行之列出一次
[root@linux ~]# uniq [-ic]
参数∶
-i  ∶忽略大小写字元的不同;
-c  ∶进行计数
范例∶
范例一∶使用 last 将帐号列出,仅取出帐号栏,进行排序后仅取出一位;
[root@linux ~]# last | cut -d ' ' -f1 | sort | uniq
范例二∶承上题,如果我还想要知道每个人的登入总次数呢?
[root@linux ~]# last | cut -d ' ' -f1 | sort | uniq -c
wc:计算行数、字数和字符数
[root@linux ~]# wc [-lwm]
参数∶
-l  ∶仅列出行;
-w  ∶仅列出多少字(英文单字);
-m  ∶多少字元;
范例∶
范例一∶那个 /etc/man.config 里面到底有多少相关字、行、字元数?
[root@linux ~]# cat /etc/man.config | wc
    138     709    4506
# 输出的三个数字中,分别代表∶ 『行、字数、字元数』
范例二∶我知道使用 last 可以输出登入者,但是 last 最后两行并非帐号内容,
        那么请问,我该如何以一行指令串取得这个月份登入系统的总人次?
[root@linux ~]# last | grep [a-zA-Z] | grep -v 'wtmp' | wc -l
# 由于 last 会输出空白行与 wtmp 字样在最底下两行,因此,我利用
# grep 取出非空白行,以及去除 wtmp 那一行,在计算行数,就能够了解!

tr:删除一段信息中的文字或者进行文字替换:
[root@linux ~]# tr [-ds] SET1 ...
参数∶
-d  ∶删除讯息当中的 SET1 这个字串;
-s  ∶取代掉重复的字元!
范例∶
范例一∶将 last 输出的讯息中,所有的小写变成大写字元∶
[root@linux ~]# last | tr '[a-z]' '[A-Z]'
范例二∶将 /etc/passwd 输出的讯息中,将冒号 (:) 删除
[root@linux ~]# cat /etc/passwd | tr -d ':'
范例三∶将 DOS 档案的断行字元 ^M 符号删除∶
[root@linux ~]# cat /home/test/dostxt | tr -d '\r' > dostxt-noM
# 那个 /r 指的是 DOS 的断行字元,关于更多的字符,请参考 man tr

col:转换Tab键
[root@linux ~]# col [-x]
参数∶
-x  ∶将 tab 键转换成对等的空白键
范例∶
[root@linux ~]# cat -A /etc/man.config  <==此时会看到很多 ^I 的符号,那就是 tab
[root@linux ~]# cat /etc/man.config | col -x | cat -A | more
# 嘿嘿!如此一来, [tab] 按键会被取代成为空白键,输出就美观多了!

#join:两个档案当中,有 "相同资料" 的那一行,将他加在一起。
[root@linux ~]# join [-ti12] file1 file2
参数∶
-t  ∶join 预设以空白字元分隔资料,并且比对『第一个栏位』的资料,
      如果两个档案相同,则将两笔资料联成一行,且第一个栏位放在第一个!
-i  ∶忽略大小写的差异;
-1  ∶这个是数字的 1 ,代表『第一个档案要用那个栏位来分析』的意思;
-2  ∶代表『第二个档案要用那个栏位来分析』的意思。
范例∶
范例一∶用 root 的身份,将 /etc/passwd 与 /etc/shadow 相关资料整合成一栏
[root@linux ~]# join -t ':' /etc/passwd /etc/shadow
bin:x:1:1:bin:/bin:/sbin/nologin:*:12959:0:99999:7:::
daemon:x:2:2:daemon:/sbin:/sbin/nologin:*:12959:0:99999:7:::
adm:x:3:4:adm:/var/adm:/sbin/nologin:*:12959:0:99999:7:::
# 因为 /etc/shadow 的权限问题,所以这里必须是 root 才能动作!而 /etc/passwd
# 与 /etc/shadow 都是以 : 来分隔栏位,所以必须要使用 -t ':' 规范栏位分隔字元。
# 且,因为 /etc/shadow 与 /etc/passwd 刚好都是以第一个栏位为帐号名称,所以,
# 就可以将同一行的资料给他贴在一起了!
# 另外,再仔细看一下 /etc/shadow 的内容与 /etc/passwd 的内容,您会发现,
# 两者都以帐号为开始,而上面的输出资料中您会发现特殊字体部分,那代表
# 第二个档案的内容。在第二个档案的内容部分,由于帐号(第一个栏位)与
# 第一的档案是相同的,所以当然就省略掉,因此就成为上面的输出。
范例二∶我们知道 /etc/passwd 第四个栏位是 GID ,那个 GID 记录在
        /etc/group 当中的第三个栏位,请问如何将两个档案整合?
[root@linux ~]# join -t ':' -1 4 /etc/passwd -2 3 /etc/group
0:root:x:0:root:/root:/bin/bash:root:x:
1:bin:x:1:bin:/bin:/sbin/nologin:bin:x:root,bin,daemon
2:daemon:x:2:daemon:/sbin:/sbin/nologin:daemon:x:root,bin,daemon
4:adm:x:3:adm:/var/adm:/sbin/nologin:adm:x:root,adm,daemon
# 这个例子就更明显了!原本的 /etc/passwd 的第一行内容应该是∶
# root:x:0:0:root:/root:/bin/bash
# 至于 /etc/group 第一行内容应该是∶
# root:x:0:
# 我将第一个档案的第四栏与第二个档案的第三栏取出,放置到输出的最前方,
# 然后将剩下的资料给他加在一起!就成了上面的输出啦!

# paste
这个 paste 就要比 join 简单多了!相对于 join 必须要比对两个档案的资料相关性, paste 就直接
『将两行贴在一起,且中间以 [tab] 键隔开』而已!简单的使用方法∶
[root@linux ~]# paste [-d] file1 file2
参数∶
-d  ∶后面可以接分隔字元。预设是以 [tab] 来分隔的!
-   ∶如果 file 部分写成 - ,表示来自 standard input 的资料的意思。
范例∶
范例一∶将 /etc/passwd 与 /etc/shadow 同一行贴在一起
[root@linux ~]# paste /etc/passwd /etc/shadow
bin:x:1:1:bin:/bin:/sbin/nologin        bin:*:12959:0:99999:7:::
daemon:x:2:2:daemon:/sbin:/sbin/nologin daemon:*:12959:0:99999:7:::
adm:x:3:4:adm:/var/adm:/sbin/nologin    adm:*:12959:0:99999:7:::
# 注意喔!同一行中间是以 [tab] 按键隔开的!
范例二∶先将 /etc/group 读出(用 cat),然后与范例一贴上一起!且仅取出前三行
[root@linux ~]# cat /etc/group|paste /etc/passwd /etc/shadow -|head -n 3
# 这个例子的重点在那个 - 的使用!那玩意儿常常代表 stdin 喔!

文件分割命令∶ split
[root@linux ~]# split [-bl] file PREFIX
参数∶
-b  ∶后面可接欲分割成的档案大小,可加单位,例如 b, k, m 等;
-l  ∶以行数来进行分割。
范例∶
范例一∶我的 /etc/termcap 有七百多K,若想要分成 300K 一个档案时?
[root@linux ~]# cd /tmp; split -b 300k /etc/termcap termcap
[root@linux tmp]# ls -l termcap*
-rw-rw-r--  1 root root  307200  8月 17 00:25 termcapaa
-rw-rw-r--  1 root root  307200  8月 17 00:25 termcapab
-rw-rw-r--  1 root root  184848  8月 17 00:25 termcapac
# 那个档名可以随意取的啦!我们只要写上前导文字,小档案就会以
# xxxaa, xxxab, xxxac 等方式来建立小档案的!
范例二∶如何将上面的三个小档案合成一个档案,档名为 termcapback
[root@linux tmp]# cat termcap* >> termcapback
# 很简单吧?就用资料流重导向就好啦!简单!
范例三∶使用 ls -al / 输出的资讯中,每十行记录成一个档案
[root@linux tmp]# ls -al / | split -l 10 - lsroot
# 重点在那个 - 啦!一般来说,如果需要 stdout/stdin 时,但偏偏又没有档案,
# 有的只是 - 时,那么那个 - 就会被当成 stdin 或 stdout ~

参数代换∶ xargs
xargs 可以读入 stdin 的资料,并且以空白字元或断行字元作为分辨,将 stdin 的资料分隔成
为 arguments作为其后的命令的参数。
[root@linux ~]# xargs [-0epn] command
参数∶
-0  ∶如果输入的 stdin 含有特殊字元,例如 `, \, 空白键等等字元时,这个 -0 参数
      可以将他还原成一般字元。这个参数可以用于特殊状态喔!
-e  ∶这个是 EOF (end of file) 的意思。后面可以接一个字串,当 xargs 分析到
      这个字串时,就会停止继续工作!
-p  ∶在执行每个指令的 argument 时,都会询问使用者的意思;
-n  ∶后面接次数,每次 command 指令执行时,要使用几个参数的意思。看范例三。
当 xargs 后面没有接任何的指令时,预设是以 echo 来进行输出喔!
范例∶
范例一∶将 /etc/passwd 内的第一栏取出,仅取三行,使用 finger 这个指令将每个
        帐号内容秀出来
[root@linux ~]# cut -d':' -f1 < /etc/passwd |head -n 3| xargs finger
Login: root                             Name: root
Directory: /root                        Shell: /bin/bash
Never logged in.
No mail.
No Plan.
......底下省略.....
# 由 finger account 可以取得该帐号的相关说明内容,例如上面的输出就是 finger root
# 后的结果。在这个例子当中,我们利用 cut 取出帐号名称,用 head 取出三个帐号,
# 最后则是由 xargs 将三个帐号的名称变成 finger 后面需要的参数!
范例二∶同上,但是每次执行 finger 时,都要询问使用者是否动作?
[root@linux ~]# cut -d':' -f1 < /etc/passwd |head -n 3| xargs -p finger
finger root bin daemon ?...y
......底下省略.....
# 呵呵!这个 -p 的参数有趣了吧?!他可以让使用者的使用过程中,被询问到每个
# 指令是否执行!
范例三∶将所有的 /etc/passwd 内的帐号都以 finger 查阅,但一次仅查阅五个帐号
[root@linux ~]# cut -d':' -f1 < /etc/passwd | xargs -p -n 5 finger
finger root bin daemon adm lp ?...y
......底下省略.....
# 在这里鸟哥使用了 -p 这个参数来让您对于 -n 更有概念。一般来说,某些指令后面
# 可以接的 arguments 是有限制的,不能无限制的累加,此时,我们可以利用 -n
# 来帮助我们将参数分成数个部分,每个部分分别再以指令来执行!这样就 OK 啦!^_^
[root@linux ~]#
范例四∶同上,但是当分析到 lp 就结束这串指令?
[root@linux ~]# cut -d':' -f1 < /etc/passwd | xargs -p -e'lp' finger
finger root bin daemon adm ?...
# 仔细与上面的案例做比较。也同时注意,那个 -e'lp' 是连在一起的,中间没有空白键。
# 上个例子当中,第五个参数是 lp 啊,那么我们下达 -e'lp' 后,则分析到 lp
# 这个字串时,后面的其他 stdin 的内容就会被 xargs 舍弃掉了!
 上面的finger命令是显示用户的详细信息。
阅读(795) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~