变量的取用与设定:echo, 变量设定规则, unset
[root@linux ~]# echo $variable
[root@linux ~]# echo $PATH
/bin:/sbin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/X11R6/bin
[root@linux ~]# echo ${PATH}
那么我要如何『设定』或者是『修改』 某个变量的内容啊?!很简单啦!用『等号(=)』连接变量与他的内容就好啦!
[root@linux ~]# echo $myname <==这里并没有任何数据~因为这个变量尚未被设定!是空的!
[root@linux ~]# myname=VBird
[root@linux ~]# echo $myname
VBird <==出现了!因为这个变量已经被设定了!
当一个变量名称尚未被设定时,预设的内容是『空』的。 另外,变量在设定时,还是需要符合某些规定的,否则会设定失败喔! 这些规则如下所示啊!
1. 变量与变量内容以等号『=』来连结;
2. 等号两边不能直接接空格符;
3. 变量名称只能是英文字母与数字,但是数字不能是开头字符;
4. 若有空格符可以使用双引号『 " 』或单引号『 ' 』来将变量内容结合起来,但须要特别留意, 双引号内的特殊字符可以保有变量特性,但是单引号内的特殊字符则仅为一般字符;
5. 必要时需要以跳脱字符『 \ 』来将特殊符号 ( 如 Enter, $, \, 空格符, ' 等 ) 变成一般符号;
6. 在一串指令中,还需要藉由其它的指令提供的信息,可以使用 quote 『 ` command` 』;(特别特别注意,那个 ` 是键盘上方的数字键 1 左边那个按键,而不是单引号!)
7. 若该变量为扩增变量内容时,则需以双引号及 $变量名称 如:『 "$PATH":/home』继续累加内容;
8. 若该变量需要在其它子程序执行,则需要以 export 来使变量变成环境变量, 如『export PATH』;
9. 通常大写字符为系统预设变量,自行设定变量可以使用小写字符,方便判断 ( 纯粹依照使用者兴趣与嗜好 ) ;
10. 取消变量的方法为:『unset 变量名称』。
--------------------------------------------------
[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 这个变量内容
[root@linux ~]# unset name
--------------------------------------------------
自订变量转成环境变量: export
当你取得一个 bash 之后,亦即得到了一个程序了,但是若你再次的执行一次 bash ,那么你将进入『子程序』,这个程序的概念我们在资源管理章节中再详谈,这里您先有个概念即可。 那么由于您已经进入了该子程序,所以在父程序中的自订变量设定将不再继续的存在。 会存在子程序中的,仅有『环境变量』。 换个角度来想,也就是说,如果我能将自订变量变成环境变量的话,那不就可以让该变量值继续存在于子程序了? 呵呵!没错!此时,那个 export 指令就很有用啦! 如您想要让该变量内容继续的在子程序中使用,那么就请执行:
export 变数
如果忘记设定 export 的话,那么不同的档案中的相同变量值,将需要一再地重复设定才行!所以,我只要在头一个档案使用 export 的话,那么后续的档案引用时,将会把该变量内容读进来!好用的很,如果仅下达 export 而没有接变量时,那么此时将会把所有的『环境变量』秀出来喔!
--------------------------------------------------
一些环境变量的说明: env
范例一:列出目前的 shell 环境下的所有环境变量与其内容。
[root@linux ~]# env
HOSTNAME=linux.dmtsai.tw <== 这部主机的主机名称
SHELL=/bin/bash <== 目前这个环境下,使用的 Shell 是哪一个程序?
TERM=xterm <== 这个终端机使用的环境是什么类型
HISTSIZE=1000 <== 这个就是『记录指令的笔数』在 FC4 预设可记录 1000 笔
USER=root <== 使用者的名称啊!
LS_COLORS=no=00:fi=00:di=00;34:ln=00;36:pi=40;33:so=00;35:bd=40;33;01:cd=40;33;01:
or=01;05;37;41:mi=01;05;37;41:ex=00;32:*.cmd=00;32:*.exe=00;32:*.com=00;32:*.btm=0
0;32:*.bat=00;32:*.sh=00;32:*.csh=00;32:*.tar=00;31:*.tgz=00;31:*.arj=00;31:*.taz=
00;31:*.lzh=00;31:*.zip=00;31:*.z=00;31:*.Z=00;31:*.gz=00;31:*.bz2=00;31:*.bz=00;3
1:*.tz=00;31:*.rpm=00;31:*.cpio=00;31:*.jpg=00;35:*.gif=00;35:*.bmp=00;35:*.xbm=00
;35:*.xpm=00;35:*.png=00;35:*.tif=00;35: <== 一些颜色显示
ENV=/root/.bashrc <== 使用的个人环境设定档
MAIL=/var/spool/mail/root <== 这个使用者所取用的 mailbox 位置
PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/X11R6/bin:/usr/local/bin:/usr/local/sbin:
/root/bin <== 不再多讲啊!是执行文件指令搜寻路径
INPUTRC=/etc/inputrc <== 与键盘按键功能有关。可以设定特殊按键!
PWD=/root <== 目前使用者所在的工作目录 (利用 pwd 取出!)
LANG=en_US.UTF-8 <== 这个与语系有关,底下会再介绍!
HOME=/root <== 这个使用者的家目录啊!
_=/bin/env <== 上一次使用的指令的最后一个参数(或指令本身)
--------------------------------------------------
• 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 宣告数值类型, 然后这样做就可以了:
--------------------------------------------------
命令别名设定: alias, unalias
命令别名是一个很有趣的东西,特别是你的惯用指令特别长的时候!还有, 增设预设的属性在一些惯用的指令上面,可以预防一些不小心误杀档案的情况发生的时候! 举个例子来说,如果你要查询隐藏档,并且需要长的列出与一页一页翻看,那么需要下达『 ls -al | more 』这个指令,我是觉得很烦啦! 要输入好几个单字!那可不可以使用 lm 来简化呢?!当然可以,你可以在命令列下面下达:
[root@linux ~]# alias lm='ls -l | more'
要注意的是:『alias 的定义规则与变量定义规则几乎相同』, 所以你只要在 alias 后面加上你的 {『别名』='指令 参数' }, 以后你只要输入 lm 就相当于输入了 ls -al|more 这一串指令!很方便吧!
另外,命令别名的设定还可以取代既有的指令喔!举例来说,我们知道 root 可以移除( rm )任何数据!所以当你以 root 的身份在进行工作时,需要特别小心, 但是总有失手的时候,那么 rm 提供了一个参数来让我们确认是否要移除该档案,那就是 -i 这个参数!所以,你可以这样做:
[root@linux ~]# alias rm='rm -i'
如何知道目前有哪些的命令别名呢?就使用 alias 呀!
[root@linux ~]# alias
alias l.='ls -d .* --color=tty'
alias ll='ls -l --color=tty'
alias lm='ls -al | more'
alias ls='ls --color=tty'
alias vi='vim'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
如果要取消命令别名的话,那么就使用 unalias 吧!例如要将刚刚的 lm 命令别名拿掉,就使用:
[root@linux ~]# unalias lm
那么命令别名与变量有什么不同呢?基本上,他们的意义就不太一样了! alias 这种命令别名,你可以将他想成是建立一个新的指令名称, 至于变量则仅是将一个数值或者字符串存在某个代表意义当中!
-------------------------------------------------
数据流重导向
数据流重导向 (redirect) 由字面上的意思来看,好像就是将『数据给他传导到其它地方去』的样子? 呵呵!是啊是啊!没错~数据流重导向就是将某个指令执行后应该要出现在屏幕上的数据, 给他传输到其它的地方,例如档案或者是装置 (例如打印机之类的!)!这玩意儿在 Linux 的文字模式底下可重要的! 尤其是如果我们想要将某些数据储存下来时,就更有用了!
我们可以将 standard error (简称 stderr) 与 standard output (简称 stdout) 给他传送到其它不同的地方,而不是屏幕上头!传送的目标处,通常是档案或者是装置! 而传送的指令则是如下所示:
1. 标准输入(stdin) :代码为 0 ,使用 < 或 << ;
2. 标准输出(stdout):代码为 1 ,使用 > 或 >> ;
3. 标准错误输出(stderr):代码为 2 ,使用 2> 或 2>> ;
举例来说,如果我想要将我目前根目录下所有的目录都记录下来的话,也就是说,将 ls -l / 这个指令的输出结果储存下来,就可以:
[root@linux ~]# ls -l / > ~/rootfile
# 本来 ls -l / 会将根目录的数据列出到屏幕上;
# 现在我使用了 > ~/rootfile 后,则本来应该在屏幕上出现的数据
# 就会被『重新导向』到 ~/rootfile 档案内了!就可以将该数据储存!
该档案的建立方式是:
1. 该档案 (本例中是 ~/rootfile) 若不存在,系统会自动的将他建立起来!
2. 当这个档案存在的时候,那么系统就会先将这个档案内容清空,然后再将数据写入!
3. 也就是若以 > 输出到一个既存盘案中,呵呵,那个档案就会被覆盖掉啰!
那如果我想要将数据累加,不想要将旧的数据删除,那该如何是好? 呵呵!就利用 >> 就好啦!例如上面的例子中,就变成『ls -l / >> ~/rootfile』 如此一来,当 ~/rootfile 不存在时,系统会主动建立这个档案,若该档案已存在, 则数据会在该档案的最下方累加进去!
• 1> :是将正确的数据输出到指定的地方去
• 2> :是将错误的数据输出到指定的地方去
我们如何将数据输出到不同的地方去呢?可以这么写:
[dmtsai@linux ~]$ find /home -name testing > list_right 2> list_error
这样一来,刚刚执行的结果中,有 Permission 的那几行错误信息都会跑到 list_error 这个档案中,至于正确的输出数据则会存到 list_right 这个档案中啰!
再来,如果我只要正确的数据,错误的信息我不要了呢?呵呵,这个时候 /dev/null 这个垃圾桶就很重要了!/dev/null 是什么呢? 基本上,那就有点像是一个『黑洞』的垃圾桶功能!当你输入的任何东西导向到这个虚拟的垃圾桶装置时, 『他就会凭空消失不见了~~』,这个东西有用的很!例如上面的例子中,我们可以这么做,来将错误的信息丢掉!
[dmtsai@linux ~]$ find /home -name testing > list_right 2> /dev/null
如果我要将数据都写到同一个档案中呢?这个时候写法需要用到特殊写法,请注意底下的写法呦!
[dmtsai@linux ~]$ find /home -name testing > list 2> list <==错误写法
[dmtsai@linux ~]$ find /home -name testing > list 2>&1 <==正确写法
OK!了解了 >, 2>, >> 与 /dev/null 之后,那么那个 < 又是什么呀!?呵呵!以最简单的说法来说, 那就是『将原本需要由键盘输入的数据,经由档案来读入』的意思。 举例来说,我们可以使用 cat 在键盘上面输入一些数据,然后写入一个档案内,例如:
[root@linux ~]# cat > catfile
testing
cat file test
<==这里按下 [ctrl]+d 结束输入来离开!
此时就会有 catfile 这个档案产生,而且该档案的内容就是刚刚输入的内容喔。 那么,我是否可以使用其它档案来取代键盘输入呢?可以啊!这样做!
[root@linux ~]# cat > catfile < somefile
我可以先编辑 somefile ,然后再以上述的指令来将数据输出到 catfile 去呢!这样可以理解了吗? 能够理解 < 之后,再来则是怪可怕一把的 << 这个连续两个小于的符号了~ 他代表的是『结束的输入字符』的意思!举例来讲:『我要用 cat 直接将输入的讯息输出到 catfile 中, 且当输入 eof 时,该次输入就结束』,那我可以这样做:
[root@linux ~]# cat > catfile <<eof
> This is a test testing
> OK now stop
> eof <==输入这个玩意儿,嘿!立刻就结束了!
----------------------------------------------------------
命令执行的判断依据: ; , &&, ||
在某些时候,我们希望可以一次执行多个指令,例如关机时,希望我可以先执行两次 sync ,然后才 shutdown 计算机,那么可以怎么作呢?这样做呀:
[root@linux ~]# sync; sync; shutdown -h now
在指令与指令中间利用分号 (;) 来隔开,这样一来,分号前的指令执行完后, 就会立刻接着执行后面的指令了。这真是方便啊~再来,换个角度来想, 万一我想要在某个目录底下建立一个档案,也就是说,如果该目录存在的话, 那我才建立这个档案,如果不存在,那就算了~目录是否存在可以使用一些 bash 提供的判断式功能, 但这里假设我不晓得那个指令,但我知道我可以使用 ls 来判断是否有该目录的存在, 也就是说,我可以利用 ls directoryname 判断是否存在,然后以 touch 建立一个档案, 这两个指令有相关性,那该如何写呢?呵呵!可以利用 && 来作喔!
[root@linux ~]# ls /tmp && touch /tmp/testingagin
如果指令执行结果没有错误讯息,那就会回传 $?=0 ,如果有错误, 那回传值就不会是 0 啊!经由这样的判断,我们也可以利用 && 来决定, 当前面的指令执行结果为正确 (例如:仅有 standard output 时),就可以接着执行后续的指令, 否则就予以略过!因此,当 ls /tmp 没有问题,那么就会接着执行 touch /tmp/testingagin 了!
再换个角度来想,如果我想要当某个档案不存在时,就去建立那个档案, 否则就略过呢?很简单啊~可以这样做:
[root@linux ~]# ls /tmp/vbirding || touch /tmp/vbirding
那个 || 刚好完全跟 && 相反,当前一个指令有错误时,在 || 后面的指令才会被执行! (要注意,那个 | 是两个 | ,而 | 按键则是反斜线 \ 同一个按键, 因此,按下 [Shift] 加上 [\] 就会出现那个 | 啰!) 因此,简单的来说,当 ls /tmp/vbirding 发生错误时,才会使用 touch /tmp/vbirding 去建立这个档案的意思。 是否很有趣啊?这个 || 及 && 对于系统管理员在管理某些档案权限、存在等问题时, 可是很有用的东西喔!
-----------------------------------------------------------
管线命令 (pipe)
如果这群数据必需要经过几道手续之后才能得到我们所想要的格式,应该如何来设定? 这就牵涉到管线命令的问题了 (pipe) ,管线命令使用的是『 | 』这个界定符号! 另外,管线命令与『连续下达命令』是不一样的呦!底下我们先举一个例子来说明一下简单的管线命令。
假设我们想要知道 /etc/ 底下有多少档案,那么可以利用 ls /etc 来查阅,不过, 因为 /etc 底下的档案太多,导致一口气就将屏幕塞满了~不知道前面输出的内容是啥?此时,我们可以透过 less 指令的协助,利用:
[root@linux ~]# ls -al /etc | less
这个管线命令『 | 』仅能处理经由前面一个指令传来的正确信息,也就是 standard output ( STDOUT ) 的信息,对于 stdandard error 并没有直接处理的能力。
在每个管线的前后部分都是『指令』呢!而后一个指令的输入乃是由前一个指令的输出而来的!
撷取命令: cut, grep
什么是撷取命令啊?说穿了,就是将一段数据经过分析后,取出我们所想要的。 或者是,经由分析关键词,取得我们所想要的那一行! 不过,要注意的是,一般来说,撷取讯息通常是针对『一行一行』来分析的, 并不是整篇讯息分析的喔~底下我们介绍两个很常用的讯息撷取命令:
• cut
这个指令可以将一段讯息的某一段给他『切』出来~ 处理的讯息是以『行』为单位喔!底下我们就来谈一谈:
[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
这个 cut 实在很好用!不过,说真的,除非你常常在分析 log 档案,否则使用到 cut 的机会并不多!好了! cut 主要的用途在于将『同一行里面的数据进行分解!』, 最常使用在分析一些数据或文字数据的时候!这是因为有时候我们会以某些字符当作分割的参数, 然后来将数据加以切割,以取得我们所需要的数据。我也很常使用这个功能呢!尤其是在分析 log 档案的时候!不过, cut 在处理多空格相连的数据时,可能会比较吃力一点~
• grep
刚刚的 cut 是将一行讯息当中,取出某部分我们想要的,而 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 的处理,就能够仅取得第一栏啰!
grep 是个很棒的指令喔!他支持的语法实在是太多了~用在正规表示法里头, 能够处理的数据实在是多的很~ 您先了解一下, grep 可以解析一行文字,取得关键词,若该行有存在关键词, 就会整行列出来!