拿计算机的运作状况来解释什么是Shell:在计算机中我们通常是通过指令来控制硬件的工作。
在Linux中硬件是如何知道你下达的指令呢?那就是 kernel(核心)的控制工作了。而Shell就是将我们输入的指令与 Kernel 沟通,好让Kernel可以控制硬件来正确无误的工作!
简单的说:替我们工作的是『硬件』,而控制硬件的是『核心』,我们使用者乃是利用『Shell』控制一些 kernel 提供的 『工具 』来操控硬件替我们正确的工作。
Unix有众多的Shell,而在Linux中使用的这一版本称为Bourne Again SHell (简称bash)
Bash Shell的功能:
1、命令编修能力:指令列按『上下键』就可以找到前一个输入的指令
2、命令与档案补全功能:
[Tab] 接在一串指令的第一个字的后面,则为命令补全;
[Tab] 接在一串指令的第二个字以后时,则为『档案补齐』!
3、命令别名(alias)设定功能:例如:alias lgx=‘ls –l /home’
取消命令别名:例如:unalias lgx
Shell的变量功能:
变量的取用与设定:echo
变量设定规则:
1. 变量与变量内容以等号 = 来连结;
2. 等号两边不能直接接空格符;
3. 变量名称只能是英文字母与数字,但是数字不能是开头字符
4. 若有空格符可以使用双引号『 " 』或单引号『 ' 』来将变量内容结合起来,但须要特别留意,双引号内的特殊字符可以保有变量特性,但是单引号内的特殊字符则仅为一般字符
5. 必要时需要以跳脱字符『 \ 』来将特殊符号 ( 如Enter, $, \, 空格符, ' 等 ) 变成一般符号
6. 若该变量为扩增变量内容时,则需以双引号及 $变量名称 如:『 "$PATH":/home』继续累加内容;
7. 若该变量需要在其它子程序执行,则需要以 export 来使变量变成环境变量, 如『export PATH』;
范例:
1、查看变量的内容:echo $PATH (注意:变量在被取用时,前面必须要加上 $ 才行)
2、设置变量:用『=』连接变量与他的内容就好了。
myname=VBird
echo $myname
VBird <==出现了!因为这个变量已经被设定了!
3、取消变量的方法:unset 变量名称
4、设定一变量name,内容为带有特殊字符·和空格(有两种方式)
name="VBird's name"
name=VBird\'s\ name #利用反斜线 (\) 跳脱特殊字符,例如单引号与空格键,这也是 OK 的啦!
单引号与双引号的区别:
单引号与双引号的最大不同在于双引号仍然可以保有变量的内容,但单引号内仅能是一般字符,而不会有特殊符号。
例如下面的例子:
[root@linux ~]# name=VBird
[root@linux ~]# echo $name
VBird
[root@linux ~]# myname="$name its me"
[root@linux ~]# echo $myname
VBird its me
[root@linux ~]# myname='$name its me'
[root@linux ~]# echo $myname
$name its me ç注意到:使用了单引号的时候,那么 $name 将失去原有的变量内容,仅为一般字符的显示型态而已!
变量的用途:
1.简化路径名称:当我们有一个比较长的路径名称时,如果手动打路径名称是个很费劲的工作。因此我们可以将路径名称写到一个变量中去,比如变量VARI ,那么以后向切换到此路径,只需要cd $VARI就可以了,很方便。
环境变量的功能:
范例:
1. 列出目前的 shell 环境下的所有环境变量与其内容:
[root@linux ~]# env
HOSTNAME=linux.dmtsai.tw <== 这部主机的主机名称
SHELL=/bin/bash <== 目前这个环境下,使用的 Shell 是哪一个程序?
TERM=xterm <== 这个终端机使用的环境是什么类型
HISTSIZE=1000 <== 这个与历史命令有关,是『记录指令的笔数』,在 FC4 预设可记录 1000 笔
USER=root <== 使用者的名称啊!
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 <== 上一次使用的指令的最后一个参数(或指令本身)
2. 其它所有的变量说明:set
set 这个指令除了会将环境变量列出来之外,其它我们的自订变量,与所有的变量,都会被列出来!可以用这个指令观察目前 shell 环境下的所有变量。
在用这个指令列出的一些变量中,比较重要的变量有这些:
PS1:(提示字符的设定) (PS1数字的1不是英文字母!)
预设的PS1内容为:'\[\u@\h \W\]\$ ' 就可以了解为何我们的提示字符会是: [root@linux ~]# 了。
假设我想要有类似底下的提示字符:[root@linux /home/dmtsai 16:50 #12]# ,那么我该如何设置呢?
这样设置PS1变量:[root@linux home]# PS1='[\u@\h \w \A #\#]\$ ' 就可以了。
3. 自订变量转成环境变量:export
自订变量与环境变量的区别主要是:环境变量可以被子程序所引用。
4. 语系档案的变量:locale
使用locate指令可以查阅我们的Linux 到底支持了多少的语系:例如输入指令:locale –a
中文语系至少支持了两种以上的编码,一种是目前还是很常见的big5 ,另一种则是越来越热门的utf-8编码。
如果发生乱码,可以设定LANG变量来解决。例如:LANG=en_US.utf8
变量键盘读取、数组与宣告:read, array, declare
1、read [-pt] variable
参数:
-p :后面可以接提示字符!
-t :后面可以接等待的秒数!这个比较有趣~不会一直等待使用者啦!
范例:
1、让使用者由键盘输入一内容,将该内容变成 atest 变量
[root@linux ~]# read atest
This is a test
[root@linux ~]# echo $atest
This is a test
2、提示使用者 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
2、declare [-aixr] variable
参数:
-a :将后面的 variable 定义成为数组 (array)
-i :将后面接的 variable 定义成为整数数字 (integer)
-x :用法与 export 一样,就是将后面的 variable 变成环境变量;
-r :将一个 variable 的变量设定成为 readonly ,该变量不可被更改内容,也不能 unset
范例:
1、让变量 sum 进行 100+300+50 的加总结果
declare -i sum=100+300+50 (如果只是单纯的sum=100+300+50,echo $sum为100+300+50,即没有效果的)
2、将sum变成环境变量:declare -x sum
3、让 sum 变成只读属性,不可更动:declare -r sum
与档案系统及程序的限制关系:ulimit
使用ulimit可以限制使用者的某些系统资源,包括可以开启的档案数量,可以使用的 CPU 时间,可以使用的内存总量等等。
范例:
1.列出所有的限制数据:ulimit -a
2.限制使用者仅能建立 1MBytes 以下的容量的档案:ulimit -f 1024
3.立刻将目前的资料写入histfile当中:history -w
在预设的情况下,会将历史纪录写入 ~/.bash_history 当中!
历史命令:history
范例:
1、列出目前最近的3笔资料:history 3
2、列出目前内存内的所有 history记忆:history
!5 执行编号为5的命令
!ls 执行最后一次以ls开头的命令
!! :就是执行上一个指令(相当于按↑按键后,按 Enter)
环境设定挡:
一、系统设定值:
1、/etc/profile 这个档案设定了几个重要的变量,例如:『PATH、USER、MAIL、 HOSTNAME、HISTSIZE、umask』等等。
需要注意的是修改了这个档案的内容,所有的使用者皆会使用到这个档案的信息。
2、/etc/bashrc 这个档案在规划 umask 的功能,也同时规划出提示字符的内容 (就是那个PS1)
二、个人设定值:
个人喜好设定所需的文件在个人家目录的几个隐藏文件中。
1、~/.bash_profile, ~/.bash_login, ~/.profile
这三个档案通常只要一个就够了,一般预设是以 ~/.bash_profile 的檔名存在。bash 启动时,会先去读取 ~/.bash_profile,找不到时,就去读取 ~/.bash_login ,然后才是 ~/.profile。
2、~/.bashrc
一般个人化设定值都会写在这里,例如命令别名、路径等等。 这个档案在您每次执行 shell script 的时候都会被重新使用一遍,所以是最完整的。 而上头的 ~/.bash_profile 则只有在登入的时候会被读取一次。
3、~/.bash_history
预设的情况下,我们的history历史命令就记录在这里!而这个档案能够记录几笔数据,则与 HISTSIZE 这个变数有关啊。每次登入 bash 后,bash 会先读取这个档案,将所有的历史指令读入内存, 因此,当我们登入 bash 后就可以查知上次使用过哪些指令啰。
4、~/.bash_logout
这个档案则记录了『当我注销 bash 后,系统再帮我做完什么动作后才离开』的意思。预设的情况下,注销时,bash 只是帮我们清掉屏幕的讯息而已。不过,你也可以将一些备份或者是其它你认为重要的工作写在这个档案中(例如清空暂存盘), 那么当你离开Linux 的时候,就可以解决一些烦人的事情啰!
设定档的读取顺序:
1. 先读取 /etc/profile ,再根据 /etc/profile 的内容去读取其它额外的设定档, 例如
/etc/profile.d 与 /etc/inputrc 等等设定档;
2. 根据不同的使用者,到使用者家目录去读取 ~/.bash_profile 或 ~/.bash_login 或 ~/.profile
等设定档;
3. 根据不同使用者,到他家目录去读取 ~/.bashrc 。
所以,当用户登入 bash 后,最终读取的设定档是~/.bashrc。也就是说,在 ~/.bashrc 里面的设定会是最终的设定值!
所以,通常是将个人的一些常用 alias 或 PATH 等环境变量或自订变量都写到这个档案去。
修改设定挡后如何生效:
一般来说,如果修改完了设定档,通常就是logout后再重新login到bash内,就能够将环境设定档重读了!不过,我们可以使用底下的方式来让该设定档立即生效:
[root@linux ~]# source ~/.bashrc
[root@linux ~]# . ~/.bashrc 利用 source 或小数点 (.) 都可以将设定档的内容读进来目前的 shell 环境中!
配置.bashrc文件可以指定某些程序在用户登陆的时候就自动启动
[第1种]在 /etc/.bashrc文件里 [修改后任何用户登录,指定程序都会自启动]
[第2种]在/home/用户名/.bashrc或/root/.bashrc文件里 [修改后,指定用户登陆后,指定程序才会自启动]
如让tomcat自启动:在.bashrc文件里的fi下面写:/home/tomcat/bin/startup.sh start
万用字符:
①* 代表0个或多个字符(或数字)
②? 代表一定有一个字母
③\ 跳脱符号,将『特殊字符或万用字符』还原成一般字符
④& 将指令变成背景下工作
⑤' 单引号,不具有变量置换的功能
⑥" 双引号,具有变量置换的功能!
⑦` ` 两个『 ` 』中间为可以先执行的指令!
⑧[ ] 在中间为字符的组合
范例:
1、cp test[1-5] /tmp 将 test1, test2, test3, test4, test5 若存在的话,就拷贝到 /tmp
2、cd /lib/modules/`uname -r`/kernel/drivers 被 ` ` 括起来的内容会先执行
万用字符[ ]详细解释:
[ ] 谨代表一个字符,而这个字符的定义可以是范围(-), 可以是指定项目,也可以是两者并存。
举例来说,我想要找出在 /etc/ 底下所有含有数字的档案, 可以这样:
ls -lda /etc/*[0-9]*
但如果我只想要找出含有 3 及 5 的档名的档案呢?就会是这样:
ls -lda /etc/*[35]*
如果是『不想要』某些范围或者是单字呢?就使用 [!] 即可!例如不想要有小写字符为开头的档案:
ls -lda /etc/[!a-z]*
数据流重导向:
> 将右边的内容写入右边的文件中(覆盖写)
>>与上面的区别是将内容追加到文件的末尾(追加)
1. 标准输入(stdin) :代码为0 ,使用< 或<< ;
2. 标准输出(stdout):代码为1 ,使用> 或>> ;
3. 标准错误输出(stderr):代码为2 ,使用2> 或2>>
在数据的重导向方面,正确的写法应该是『1>』与『2>』才对!但是如果只有 > 则预设是以 1> 来进行数据的!那个 1> 是输出正
确数据, 2> 则是错误数据输出项目。也就是说:
• 1> :是将正确的数据输出到指定的地方去
• 2> :是将错误的数据输出到指定的地方去
范例:
Find /home -name testing > list_right 2> list_error
如果不想要错误的信息,可以使用/dev/null这个垃圾桶,/dev/null有点像是一个黑洞的垃圾桶功能!当你输入的任何东西导向到这个虚拟的垃圾桶装置时,他就会凭空消失不见了。
例如:find /home -name testing > list_right 2> /dev/null
命令执行的判断依据: ; , &&, ||
1、在某些时候,我们希望可以一次执行多个指令:
例如:[root@linux ~]# sync; sync; shutdown -h now
在指令与指令中间利用分号 (;) 来隔开,这样一来,分号前的指令执行完后, 就会立刻接着执行后面的指令了。
2、使用&&命令使前后两个指令有关联!比如前面指令执行结果正确后才执行后面的指令;如果前面的指令执行有错,那么后面的指令则不会执行。
ls /tmp && touch /tmp/testingagin 作用是:判断是否有tmp目录,如果有,则在tmp目录下面创建testingagin目录
3、与&&相反的则是||命令!它表示当前一个指令有错误时,在 || 后面的指令才会被执行!
使用&&和||来进行命令中的逻辑判断:
ls /tmp/vbirding && echo "exist" || echo "not exist"
意思是说,当 ls /tmp/vbirding 执行后,若正确,就执行 echo "exist" ,若有问题,就执行 echo "not exist" !
管道命令 |:把上一个命令的结果交给| 后面的命令处理
比如这样使用:ls –l /etc/ | more
撷取命令: cut, grep
1、cut:cut 就是切的意思。这个指令可以将一段讯息的某一段给他切出来,处理的讯息是以行为单位。
[root@linux ~]# cut -d'分隔字符' -f fields
[root@linux ~]# cut -c 字符区间
参数:
-d :后面接分隔字符。与 -f 一起使用;
-f :依据 -d 的分隔字符将一段讯息分割成为数段,用 -f 取出第几段的意思;
-c :以字符 (characters) 的单位取出固定字符区间;
范例:
1、将 PATH 变量取出,我要找出第三个路径:echo $PATH | cut -d ':' -f 3
2、如果想要列出第 3 与第 5 个呢:echo $PATH | cut -d ':' -f 3,5
3、将 export 输出的讯息,取得第 12 字符以后的所有字符串: export | cut -c 12-
# 用 -c 可以处理比较具有格式的输出数据!
# 我们还可以指定某个范围的值,例如第 12-20 的字符,就是 cut -c 12-20!如果是12-则取的是12行以后的数据。
2、grep:cut是将一行讯息当中,取出某部分我们想要的。而 grep 是分析一行信息,若当中有我们所需要的信息,就将该行拿来。
语法:grep [-acinv] '搜寻字符串' filename
参数:
-a :将 binary 档案以 text 档案的方式搜寻数据
-c :计算找到 '搜寻字符串' 的次数
-i :忽略大小写的不同,所以大小写视为相同
-n :顺便输出行号
-v :反向选择,亦即显示出没有 '搜寻字符串' 内容的那一行
范例:
①在 last 的输出讯息中,只要有 root 就取出,并且仅取第一栏:last | grep 'root' |cut -d ' ' -f1
②将/var/log/secure这个档案中有 root 的那一行秀出来:grep 'root' /var/log/secure
③利用[ ]来搜寻集合字符:搜寻test 或tast这两个单字:grep -n 't[ae]st' regular_express.txt
其实[ ]里面不论有几个字符,他都仅代表某一个字符,所以,上面的例子说明了,我需要的字符串是tast或test两个字符串而已。
④如果我在搜寻aa字符串时,不想前面有g的话,可以利用在集合字符的反向选择[^] 来达成:grep -n '[^g]aa' regular_express.txt
⑤如果不想在搜寻aa时,前面有小写的字符,可以这样:grep -n '[^a-z]aa' regular_express.txt
⑥行首与行尾字符^ $:搜寻the这个单词出现在行首列的行:grep -n '^[a-z]' regular_express.txt
注意:那个^ 符号,在[ ]内代表『反向选择』,在[ ]之外则代表定位在行首的意义!
⑦任意一个字符. 与重复字符 *
假设我需要找出g??d 的字符串:grep -n 'g..d' regular_express.txt
* 代表的是:重复0个或多个前面的字符
o*代表:拥有空字符或一个o 以上的字符
oo*代表:第一个o 肯定必须要存在,第二个o 则是可有可无的多个o
⑧限定连续字符范围{}
因为{ 与} 的符号在shell 是有特殊意义的,因此, 我们必须要使用跳脱字符\ 来让他失去特殊意义才行。
假设我要找到两个o 的字符串,可以是:grep -n 'o\{2\}' regular_express.txt
要找出g 后面接2 到5 个o ,然后再接一个g 的字符串:grep -n 'go\{2,5\}g' regular_express.txt
排序命令:sort、wc、uniq
1、sort指令:
它可以帮我们进行排序,可以依据不同的数据型态来排序。此外排序的字符与语系的编码有关,因此如果您需要排序时,建议使用 LC_ALL=C 来让语系统一,数据排序比较好一些。
语法:sort [-fbMnrtuk] [file or stdin]
参数:
-f :忽略大小写的差异,例如 A 与 a 视为编码相同;
-M :以月份的名字来排序,例如 JAN, DEC 等等的排序方法;
-n :使用纯数字进行排序(预设是以文字型态来排序的);
-r :反向排序;
-u :就是 uniq ,相同的数据中,仅出现一行代表;
-k :以那个区间 (field) 来进行排序的意思
-t :分隔符,预设是 tab 键;
如果只输入sort,不带任何参数,sort 是预设以第一个数据来排序,而且预设是以文字型态来排序的喔!所以由 a 开始排到最后。
范例:
1. /etc/passwd 内容是以 : 来分隔的,我想根据第三栏来排序:cat /etc/passwd | sort -t ':' -k 3
2.将上面的排序改成以数字排序:cat /etc/passwd | sort -t ':' -k 3 –n
2、uniq指令
如果我排序完成了,想要将重复的资料仅列出一个显示,这可以用uniq来实现。
语法:uniq [-ic]
参数:
-i :忽略大小写字符的不同;
-c :进行计数
范例:
1. 使用 last 将账号列出,仅取出账号栏,进行排序后仅取出一位:last | cut -d ' ' -f1 | sort | uniq
2. 承上题,如果我还想要知道每个人的登入总次数呢:last | cut -d ' ' -f1 | sort | uniq -c
3、wc命令:查看一个档案里面有多少字?多少行?多少字符?
wc [-lwm]
参数:
-l :仅列出行;
-w :仅列出多少字(英文单字);
-m :多少字符;
范例:
cat /etc/man.config | wc
138 709 4506 # 输出的三个数字中,分别代表: 『行、字数、字符数』
字符转换命令: tr, col, join, paste, expand
1、tr:可以用来删除一段讯息当中的文字,或者是进行文字讯息的替换!
参数:
-d :删除讯息当中的 SET1 这个字符串;
-s :取代掉重复的字符!
范例:
1.将 last 输出的讯息中,所有的小写变成大写字符: last | tr '[a-z]' '[A-Z]'
2.将 /etc/passwd 输出的讯息中,将冒号 (:) 删除 cat /etc/passwd | tr -d ':'
分割命令:split
如果你有档案太大,导致一些携带式装置无法复制的问题,可以用split来解决!他可以帮你将一个大档案,依据档案大小或行数来分割,就可以将大档案分割成为小档案了。快速又有效啊。
split [-bl] file PREFIX
参数:
-b :后面可接欲分割成的档案大小,可加单位,例如 b, k, m 等;
-l :以行数来进行分割。
范例:
1.我的 /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 等方式来建立小档案的!
2.如何将上面的三个小档案合成一个档案,档名为 termcapback
cat termcap* >> termcapback # 很简单吧?就用数据流重导向就好啦!简单!
显示和设置系统日期和时间:date
给定格式控制输出:
%Y 年份
%m 月份(01-12)
%d 按月计的日期(例如:01-30)
%H 小时(00-23)
%M 分(00-59)
%S 秒(00-60)
范例:
显示系统时间:$date 显示结果是:Thu Dec 5 22:55:41 WIB 2013
格式化显示日期:$date -R:显示结果是:Thu, 05 Dec 2013 23:40:53 +0700 RFC 2822的格式:星期, 日-月-年, 小时:分钟:秒 时区
date "+%Y-%m-%d" 2013-02-19
date "+%H:%M:%S" 13:13:59
date "+%Y-%m-%d %H:%M:%S" 2013-02-19 13:14:19
date "+%Y_%m_%d %H:%M:%S" 2013_02_19 13:14:58
date -d today Tue Feb 19 13:10:38 CST 2013
date -d now Tue Feb 19 13:10:43 CST 2013
date -d tomorrow Wed Feb 20 13:11:06 CST 2013
date -d yesterday Mon Feb 18 13:11:58 CST 2013