学习Bash Shell

拿计算机的运作状况来解释什么是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

1read [-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 

 

2declare [-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+50echo $sum100+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  这个档案设定了几个重要的变量,例如:『PATHUSERMAIL、 HOSTNAMEHISTSIZEumask』等等。

需要注意的是修改了这个档案的内容,所有的使用者皆会使用到这个档案的信息。

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后再重新loginbash内,就能够将环境设定档重读了!不过,我们可以使用底下的方式来让该设定档立即生效: 

[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]*

但如果我只想要找出含有 及 的档名的档案呢?就会是这样: 

ls -lda /etc/*[35]*

如果是『不想要』某些范围或者是单字呢?就使用 [!] 即可!例如不想要有小写字符为开头的档案: 

ls -lda /etc/[!a-z]*

 

数据流重导向:

将右边的内容写入右边的文件中(覆盖写)

>>与上面的区别是将内容追加到文件的末尾(追加)

1.  标准输入(stdin) :代码为,使用<< 

2.  标准输出(stdout):代码为,使用>> 

3.  标准错误输出(stderr):代码为,使用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

1cutcut 就是切的意思。这个指令可以将一段讯息的某一段给他切出来,处理的讯息是以行为单位。

[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、如果想要列出第 与第 个呢:echo $PATH | cut -d ':' -f 3,5

3、将 export 输出的讯息,取得第 12 字符以后的所有字符串: export | cut -c 12-

用 -c 可以处理比较具有格式的输出数据! 

我们还可以指定某个范围的值,例如第 12-20 的字符,就是 cut -c 12-20!如果是12-则取的是12行以后的数据。

 

2、grepcut是将一行讯息当中,取出某部分我们想要的。而 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

  其实[ ]里面不论有几个字符,他都仅代表某一个字符,所以,上面的例子说明了,我需要的字符串是tasttest两个字符串而已。

④如果我在搜寻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*代表:拥有空字符或一个以上的字符

oo*代表:第一个肯定必须要存在,第二个则是可有可无的多个

⑧限定连续字符范围{}

因为的符号在shell 是有特殊意义的,因此, 我们必须要使用跳脱字符来让他失去特殊意义才行。

假设我要找到两个的字符串,可以是:grep -n 'o\{2\}' regular_express.txt

要找出后面接,然后再接一个的字符串:grep -n 'go\{2,5\}g' regular_express.txt

 

排序命令:sortwcuniq

1sort指令:

它可以帮我们进行排序,可以依据不同的数据型态来排序。此外排序的字符与语系的编码有关,因此如果您需要排序时,建议使用 LC_ALL=C 来让语系统一,数据排序比较好一些。

语法:sort [-fbMnrtuk] [file or stdin] 

参数: 

-f :忽略大小写的差异,例如 与 视为编码相同; 

-M :以月份的名字来排序,例如 JAN, DEC 等等的排序方法; 

-n :使用纯数字进行排序(预设是以文字型态来排序的); 

-r :反向排序; 

-u :就是 uniq ,相同的数据中,仅出现一行代表; 

-k :以那个区间 (field) 来进行排序的意思

-t :分隔符,预设是 tab 键;

如果只输入sort,不带任何参数,sort 是预设以第一个数据来排序,而且预设是以文字型态来排序的喔!所以由 开始排到最后。

范例:

1. /etc/passwd 内容是以 来分隔的,我想根据第三栏来排序:cat /etc/passwd | sort -t ':' -k 3

2.将上面的排序改成以数字排序:cat /etc/passwd | sort -t ':' -k 3 –n

 

2uniq指令

如果我排序完成了,想要将重复的资料仅列出一个显示,这可以用uniq来实现。

语法:uniq [-ic] 

参数: 

-i :忽略大小写字符的不同; 

-c :进行计数

范例:

1. 使用 last 将账号列出,仅取出账号栏,进行排序后仅取出一位:last | cut -d ' ' -f1 | sort | uniq

2. 承上题,如果我还想要知道每个人的登入总次数呢:last | cut -d ' ' -f1 | sort | uniq -c

 

3wc命令:查看一个档案里面有多少字?多少行?多少字符?

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 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值