Shell脚本基础I

时间:2022-03-29 12:24:14

1、Linux shell类型
/bin/sh--已经被/bin/bash所取代
/bin/bash--就是Linux预设的shell
/bin/ksh--由AT&T Bell lab发展出来的,兼容于bash
/bin/tcsh--整合C Shell,提供更多的功能
/bin/csh--已经被/bin/tcsh所取代
/bin/zsh--基于ksh发展出来的,功能更强大的shell

2、Bash的内建命令:type
[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

3、变量设定规则(echo、unset)
变量在设定时还是需要符合某些规定的,否则会设定失败,这些规则如下:
1)变量与变量内容以等号=来连结;
2)等号两边不能直接接空格符;
3)变量名称只能是英文字母与数字,但是数字不能是开头字符;
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

4、查看环境变量--env
范例一:列出目前的shell环境下的所有环境变量与其内容。
[root@linux ~]# env
HOSTNAME=linux.dmtsai.tw    <== 这部主机的主机名称
SHELL=/bin/bash    <== 目前这个环境下,使用的Shel是哪一个程序?
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    <== 上一次使用的指令的最后一个参数(或指令本身)

那么上面这些变量有些什么功用呢?
1)HOME:代表使用者的家目录。可以使用 cd ~ 去到使用者的家目录或者利用cd就可以直接回到使用者家目录了
2)SHELL:告知我们目前这个环境使用的SHELL是哪支程序? 如果是bash的话,预设是/bin/bash
3)HISTSIZE:这个与『历史命令』有关,亦即是曾经下达过的指令可以被系统记录下来,而记录的笔数则是由这个值来设定的
4)ENV:这个使用者所使用的个人化环境设定档的读取档案
5)MAIL:当我们使用mail这个指令在收信时,系统会去读取的邮件信箱档案(mailbox)。
6)PATH:就是执行文件搜寻的路径~目录与目录中间以冒号(:)分隔,由于档案的搜寻是依序由PATH的变量内的目录来查询,所以目录的顺序也是重要
7)LANG: 这个是语系档案~很多数据都会用到他,举例说,当我们在启动某些perl的程序语言档案时,他会主动的去分析语系数据文件,如果发现有他无法解析的编码

语系可能会产生错误!一般来说,我们中文编码通常是zh_TW.Big5或者是zh_TW.UTF-8这两个编码,偏偏不容易被解译出来,所以有的时候可能需要修订一下语系数据。
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
8 <== 此时会随机取出 0~9 之间的数值喔!

5、查看所有变量--set
[root@linux ~]# set
BASH=/bin/bash    <== bash的主程序放置路径
BASH_VERSINFO=([0]="3" [1]="00" [2]="16" [3]="1" [4]="release"
[5]="i386-redhat-linux-gnu")    <== bash的版本啊
BASH_VERSION='3.00.16(1)-release'    <== bash的版本
COLORS=/etc/DIR_COLORS.xterm    <== 使用的颜色纪录档案
COLUMNS=115    <== 在目前的终端机环境下,使用的字段有几个字符长度
HISTFILE=/root/.bash_history     <== 历史命令记录的放置档案,隐藏档
HISTFILESIZE=1000    <== 存起来(与上个变量有关)的档案之指令的最大纪录笔数
HISTSIZE=1000    <== 目前环境下,可记录的历史命令最大笔数
HOSTTYPE=i386    <== 主机安装的软件主要类型。我们用的是i386兼容机器软件
IFS=$' \t\n'    <== 预设的分隔符
LINES=35    <== 目前的终端机下的最大行数
MACHTYPE=i386-redhat-linux-gnu    <== 安装的机器类型
MAILCHECK=60    <== 与邮件有关,每60秒去扫瞄一次信箱有无新信
OLDPWD=/home    <== 上个工作目录
OSTYPE=linux-gnu    <== 操作系统的类型
PPID=20046    <== 父程序的PID
PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME%%.*}:${PWD/#$HOME/~}\007"'    <== 命令提示字符,与底下也有关
PS1='[\u@\h \W]\$ '     <== PS1命令提示字符
RANDOM=13586     <== 随机数
SUPPORTED=zh_TW.UTF-8:zh_TW:zh:en_US.UTF-8     <== 本系统所支持的语系
name=VBird    <== 刚刚设定的自订变量也可以被列出来
$     <== 目前这个shell所使用的PID
?     <== 刚刚执行完指令的回传值
    使用set除了会将系统的默认值秀出来之外,连带的所有的你自己设定的变量也会被秀出来,同时需要注意的是,若当时有相当多人同时在线的话,那么你的变量只

能给自己使用(除非改的是系统的预设参数档,如/etc/profile ),而不会干扰到别人的。

6、自订变量转成环境变量--export
[root@linux ~]# export
declare -x ENV="/root/.bashrc"
declare -x HISTSIZE="1000"
declare -x HOME="/root"
declare -x HOSTNAME="linux.dmtsai.tw"
declare -x INPUTRC="/etc/inputrc"
declare -x LANG="en_US.UTF-8"
declare -x MAIL="/var/spool/mail/root"
declare -x SHELL="/bin/bash"

7、语系档案的变量--locale
[root@linux ~]# locale -a
aa_DJ
aa_DJ.iso88591
en_US
en_US.iso88591
en_US.iso885915
en_US.utf8
zh_TW
zh_TW.big5
zh_TW.euctw
zh_TW.utf8
中文语系至少支持了两种以上的编码,一种是目前还是很常见的big5 ,另一种则是越来越热门的utf-8编码。那么我们如何修订这些编码呢?其实可以透过底下这些变量

的:
[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 <==语言环境的整体设定。

8、要读取来自键盘输入的变量--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

9、宣告变量的属性--declare / typeset
    declare或typeset是一样的功能。如果使用declare后面并没有接任何参数,那么bash就会主动的将所有的变量名称与内容通通叫出来,就好像使用set一样。
[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 <==不能改这个变数了

10、与档案系统及程序的限制关系--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

11、额外的变量设定功能
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
   如果变量后面接的是/时,那么表示后面是进行取代的工作~而且仅取代第一个,但如果是//,则表示全部的字符串都取代。

12、变量设定方式
str                             没有设定                         str为空字符串                  str已设定非为空字符串

Shell脚本基础I

范例一:若str变量内容存在,则var设定为str ,否则var设定为"newvar"
[root@linux ~]# unset str; var=${str-newvar}
[root@linux ~]# echo var="$var", str="$str"
var=newvar, str=     <==因为str不存在,所以var为newvar
[root@linux ~]# str="oldvar"; var=${str-newvar}
[root@linux ~]# echo var="$var", str="$str"
var=oldvar, str=oldvar    <==因为str存在,所以var等于str的内容

范例二:若str不存在,则var与str均设定为newvar,否则仅var为newvar
[root@linux ~]# unset str; var=${str=newvar}
[root@linux ~]# echo var="$var", str="$str"
var=newvar, str=newvar    <==因为str不存在,所以var/str均为newvar
[root@linux ~]# str="oldvar"; var=${str=newvar}
[root@linux ~]# echo var="$var", str="$str"
var=oldvar, str=oldvar    <==因为str存在,所以var等于str的内容

范例三:若str这个变量存在,则var等于str,否则输出"novar"
[root@linux ~]# unset str; var=${str?novar}
-bash: str: novar    <==因为str不存在,所以输出错误讯息
[root@linux ~]# str="oldvar"; var=${str?novar}
[root@linux ~]# echo var="$var", str="$str"
var=oldvar, str=oldvar    <==因为str存在,所以var等于str的内容

13、命令别名设定--alias,unalias
[root@linux ~]# alias lm='ls -l | more'
[root@linux ~]# alias rm='rm -i'
[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'

[root@linux ~]# unalias lm

14、历史命令--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个)

15、登录讯息显示数据--/etc/issue,/etc/motd

16、环境设定
1)系统设定值
   每个使用者进入到bash shell之后,会先读取的设定档案,预设的设定档案有下列几个:
/etc/sysconfig/i18n
/etc/profile
/etc/bashrc
/etc/profile.d/*.sh
/etc/man.config

2)个人设定值
   个人的喜好设定:
~/.bash_profile,~/.bash_login,~/.profile
~/.bashrc
~/.bash_history
~/.bash_logout

3)登入bash的时候,这些设定档到底是如何读取的呢?
   先读取/etc/profile,再根据/etc/profile的内容去读取其它额外的设定档, 例如/etc/profile.d与/etc/inputrc等;
   根据不同的使用者,到使用者家目录去读取~/.bash_profile或~/.bash_login或~/.profile等;
   根据不同使用者,到他家目录去读取~/.bashrc

Shell脚本基础I

4)bash命令运作顺序

a、以相对/绝对路径执行指令,例如/bin/ls或./ls;

b、由alias找到该指令来执行;

c、由bash内建的 (builtin) 指令来执行;

d、透过$PATH这个变量的顺序搜寻到的第一个指令来执行。

17、终端机的环境设定--stty,set
1)stty
stty也可以帮助设定终端机的输入按键代表意义。
[root@linux ~]# stty [-a]
参数:
-a:将目前所有的 stty 参数列出来;
范例一:列出所有的按键与按键内容
[root@linux ~]# stty -a
speed 38400 baud; rows 40; columns 80; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = ;
eol2 = ; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase
= ^W; lnext = ^V; flush = ^O; min = 1; time = 0;
-parenb -parodd cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl
ixon -ixoff -iuclc -ixany -imaxbel opost -olcuc -ocrnl onlcr -onocr
-onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0 isig icanon iexten
echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke
   可以利用stty -a来列出目前环境中所有的按键列表,在上头的列表当中,需要之前提到一些变量时,可以利用set来显示,除此之外,其实set还可以帮我们设定整个指令输出/输入的环境。 例如记录历史命令、显示错误内容等。

2)set
[root@linux ~]# set [-uvCHhmBx]
参数:
-u:预设不启用。若启用后,当使用未设定变量时,会显示错误讯息;
-v:预设不启用。若启用后,在讯息被输出前,会先显示讯息的原始内容;
-x:预设不启用。若启用后,在指令被执行前,会显示指令内容(前面有++符号);
-h:预设启用。与历史命令有关;
-H:预设启用。与历史命令有关;
-m:预设启用。与工作管理有关;
-B:预设启用。与刮号[]的作用有关;
-C:预设不启用。若使用>等,则若档案存在时该档案不会被覆盖。
范例一:显示目前所有的set设定值
[root@linux ~]# echo $-
himBH
    那个$-变量内容就是set的所有设定,bash预设是himBH。

范例二:设定"若使用未定义变量时,则显示错误讯息"
[root@linux ~]# set -u
[root@linux ~]# echo $vbirding
-bash: vbirding: unbound variable
   预设情况下,未设定/未宣告的变量都会是空的,不过若设定-u参数,那么当使用未设定的变量时,就会有问题,很多的shell都预设启用-u参数。若要取消这个参数

,输入set +u即可。

范例三:执行前显示该指令内容。
[root@linux ~]# set -x
[root@linux ~]# echo $HOME
+ echo /root
/root
++ echo -ne '\033]0;root@linux:~\007'
    要输出的指令都会先被打印到屏幕上,前面会多出+的符号。

18、万用字符与特殊符号
   在bash里还支持一些万用字符(wild card),利用bash处理数据就更方便了,底下我们列出一些常用的万用字符:
*  万用字符,代表0个或多个字符(或数字)
?  万用字符,代表一定有一个字母
#  批注,这个最常被使用在script当中,视为说明
\  跳脱符号,将特殊字符或万用字符还原成一般字符
|  分隔两个管线命令的界定
;  连续性命令的界定
~  使用者的家目录
$  亦即是变量之前需要加的变量取代值(间接引用:\$$)
&  将指令变成背景下工作
!  逻辑运算意义上的非not的意思
/  路径分隔的符号
>, >>  输出导向,分别是取代与累加
'  单引号,不具有变量置换的功能
"  具有变量置换的功能!
` `  两个`中间为可以先执行的指令
( )  在中间为子shell的起始与结束
[ ]  在中间为字符的组合
{ }  在中间为命令区块的组合
\<,\>正则表达式单词边界
>| 强制重定向
~+ 当前工作目录
~- 之前的工作目录
<<,<< = n 左移1/n位
>>,>> = n 右移1/n位
~  按位非
&  按位与
|  按位或
^  按位异或
&&  逻辑与,同-a
||  逻辑或,同-o

组合按键  执行结果
Ctrl + C  终止目前的命令
Ctrl + D  输入结束(EOF)
Ctrl + M  就是Enter
Ctrl + S  暂停屏幕的输出
Ctrl + Q  恢复屏幕的输出
Ctrl + U  在提示字符下将整列命令删除
Ctrl + Z  暂停目前的命令

19、数据流重导向
1)标准输入(stdin):代码为0,使用<或<<;
2)标准输出(stdout):代码为1,使用>或>>;
3)标准错误输出(stderr):代码为2,使用2>或2>>;
1>:是将正确的数据输出到指定的地方去
2>:是将错误的数据输出到指定的地方去
[dmtsai@linux ~]$ find /home -name testing > list 2> list <==错误写法
[dmtsai@linux ~]$ find /home -name testing > list 2>&1 <==正确写法
< 是什么?
   就是将原本需要由键盘输入的数据,经由档案来读入的意思。举例来说,可以使用cat在键盘上面输入一些数据,然后写入一个档案内,例如:
[root@linux ~]# cat > catfile
testing
cat file test
<==这里按下[ctrl]+d结束输入来离开

常用重定向:
2>&1  重定向stdrr到stdout
i>&j  重定向文件描述符i到j
>&j   默认的重定向文件描述符1(stdout)到j
0<FILENAME
<FILENAME    从文件中接受输入
n<&_  关闭输入文件描述符n
0<&_
<&_   关闭标准输入
n>&_  关闭输出文件描述符
1>&_
>&_   关闭标准输出
exec <FILENAME 后面的输入都来自文件filename
exec 6<&0 将标准输入保存在文件描述符6中
exec 0<&6,6<&_  标准输入从文件描述符6中恢复,并关闭文件描述符6

20、命令执行的判断依据 -- ;  &&  ||
       管线命令 -- |

21、一些字符/字符串处理命令
1)grep
[root@linux ~]# grep [-acinv] '搜寻字符串' filename
参数:
-a:将binary档案以text档案的方式搜寻数据
-c:找到'搜寻字符串'的次数
-i:忽略大小写的不同
-n:顺便输出行号
-v:反向选择,亦即显示出没有'搜寻字符串'内容的那一行
-R:递归搜索文件中文本
-w:只搜索整个词
-l:列出包含搜索内容的文件名
范例一:将last当中有出现root的那一行就取出来
[root@linux ~]# last | grep 'root'
范例二:与范例一相反,只要没有root的就取出
[root@linux ~]# last | grep -v 'root'
范例三:在last的输出讯息中,只要有root就取出并且仅取第一栏
[root@linux ~]# last | grep 'root' |cut -d ' ' -f1

grep -G(grep) 基本准则表达式
grep -E(egrep) 扩展准则表达式
grep -F(fgrep)固定字符串列表,匹配其中任何一项
grep -P  Perl准则表达式
查看文件中搜索内容的上下文信息:
-A  之前
-B  之后
-C  之前和之后

2)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那一行。

3)双向重导向: tee
   同时将数据流分送到档案去与屏幕(screen);而输出到屏幕的其实就是stdout,可以让下个指令继续处理。
[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这个参数才能将讯息累加。

4)expand
   这玩意儿就是在将[tab]按键转成空格键。
[root@linux ~]# expand [-t] file
参数:
-t:后面可以接数字。一般来说一个tab按键可以用8个空格键取代。也可以自行定义一个tab按键代表多少个字符。
范例一:将/etc/man.config内行首为MANPATH的字样就取出;仅取前三行;
[root@linux ~]# grep '^MANPATH' /etc/man.config | head -n 3
MANPATH /usr/man
MANPATH /usr/share/man
MANPATH /usr/local/man

范例二:承上,如果我想要将所有的符号都列出来?(用cat)
[root@linux ~]# grep '^MANPATH' /etc/man.config | head -n 3 |cat -A
MANPATH^I/usr/man$
MANPATH^I/usr/share/man$
MANPATH^I/usr/local/man$
   tab]按键可以被cat -A显示成为^I

范例三:承上,我将tab按键设定成6个字符
[root@linux ~]# grep '^MANPATH' /etc/man.config | head -n 3 | expand -t 6 - | cat -A
MANPATH /usr/man$
MANPATH /usr/share/man$
MANPATH /usr/local/man$
123456123456123456.....
    因为是以6个字符来代表一个tab的长度,所以MAN...到/usr之间会隔12(两个tab个字符,如果tab改成9的话情况就又不同了。

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