《shell十三问》学习笔记

shell十三问地址:http://bbs.chinaunix.net/thread-218853-1-1.html


一、为何叫做shell

           硬件的驱动和文件的管理需要通过操作系统来处理,而对于linux操作系统来说,使用者没法直接操作kernel,而是通过kernel的外壳来操作,这个外壳就是shell。

           shell最简单的定义就是命令解释器:将使用者的命令翻译给kernel处理;同时将kernel处理的结果翻译给使用者。


            在linux的预设系统中,通常有几种不同的shell,保存在/etc/shells里;常见的shell分为两大主流:

                             sh:

                                                 burne  shell(sh)

                                                 burne  again  shell(bash)

                            csh:

                                                 c  shell(csh)

                                                 tc  shell(tcsh)

                                                 korn  shell(ksh)


二、shell  prompt(PS1)与Carriage Return(CR)


在linux上,可见的提示符一般是两种:

         $:给一般使用者使用

         #:给root使用

用户在shell  prompt命令出现之后才能输入命令行,直到碰到CR(就是由Enter键产生)字符为止;

shell会依据IFS将命令行所输入的文字拆解为字段,然后在针对特殊字符先做处理,最后再重组整行。


IFS:shell预设使用的字段分隔符,可以由一个或者多个如下按键组成:

空格键

制表符

回车键



三、echo相关

-n选项:取消换行符

-e:启用反斜线转义字符

-E:关闭反斜线转义字符



四、双引号”“与单引号‘’的区别

shell将命令行的每一个字符分为两种:

(1)literal:普通的纯文字

(2)meta:具有特定功能的特殊保留字符


常见的meta:

IFS:空格、制表符、回车键

CR:由回车键产生

=:设定变量

$:做变量或运算替换

>:重定向stdout

<:重定向stdin

|:管道

&:重定向文件描述符,或将命令在后台执行

():将期内的命令至于nested  subshell执行,或用于运算或命令替换

{}:将期内的命令置于non-named function中执行,或用在变量替换的界定范围

;:在前一个命令结束时,忽略其返回值,继续执行下一个命令

&&:在前一个命令结束时,若返回值为true,继续执行下一个命令。

||:在前一个命令结束时,若其返回值为false,继续执行下一个命令

!:执行history列表中的命令



假如在命令行中将这些保留字符的功能关闭的话,就需要quoting处理了:

在bash中,常用的quoting有如下三种方法:

hard  quote:‘’单引号,凡在hard quote中的所有meta均被关闭。

soft  quote:”“双引号,在soft quote中大部分meta都会被关闭,但某些则被保留,如$,/,单引号

escape:\反斜线,只有紧接在escape(跳脱字符)之后的单一meta才被关闭


或者说,单引号就是指将保留字符全部关闭,单引号中的所有字符均会原样输出;双引号的某些特殊字符会被引用,输出的是经过转移之后。


a='b  c'

echo  ‘$a'

$a

echo "$a"

b    c

hangma@ubuntu:/home$ echo "sjf'$a'"
sjf'b c'

上面的例子在双引号中引用单引号会保留单引号,但是单引号中的内容依然会进行转义
hangma@ubuntu:/home$ echo '$adksjfkds"skdjfkdsj$a"'
$adksjfkds"skdjfkdsj$a"

上面的例子在单引号中引用双引号,但是双引号中的内容都不会进行转义



五、变量相关

1、变量就是利用一个特定的名称来存储一段可以变化的值

设定变量的规则:

(1)可以利用”=“来设定或重新定义变量的内容

(2)等号左右两边不能使用区隔符号(IFS),也应避免使用shell的保留字符

(3)变量名称不能使用$符号

(4)变量名称的第一个字母不能是数字

(5)变量名称长度不能超过256个字母

(6)变量名称及变量值大小写是有区别的


所谓的设定变量,就是用一个名称储存一个数值;


2、export

严格说来,在当前shell中所定义的变量都属于”本地变量“,只有经过export命令的”输出“处理,才能成为环境变量。


取消变量:unset名里那个


区别:

A=

unset   A

第一行是将变量A设定为空值(NULL value),但第二行是让变量A不再存在。

比较这两者的不同:

(1)如果是unset  A

var=${A=expr}

则结果是:

var=expr

A=expr

(2)如果是A=

var=${A=expr}

则结果是:

var=

A=



六、exec和source的差别:

1、所谓环境变量起始就是那些会传给子进程的变量;遗传性就是区分本地变量与环境变量的决定性指标;

环境变量只能从父进程到子进程单向继承;换句话说,在子进程中的环境如何变更,均不会影响父进程的环境。



2、正常来说,当我们执行一个shell script时,其实是先产生一个sub-shell的子进程,然后sub-shell再去产生命令行的子进程。


为什么  cd  /etc/aa/bb/cc写入shell脚本时,shell不执行?

因为,一般shell 脚本使用subshell去执行的,从进程的观念来看,是父进程产生一个子进程去执行,当子进程结束后,会返回父进程,但是父进程的环境不会因为子进程的改变而改变,所谓的环境变量数目很多,其中工作目录($PWD)正是问题所在,当subshell执行脚本时,subshell的$PWD会因为cd而变更,但当返回父进程shell时,$PWD是不会变更的。


所谓source就是让script在当前的shell内执行,而不是产生一个subshell来执行;由于所有执行结果均于当前shell内完成,若script的环境有所改变,当然也会改变当前环境;

因此,只要我们要将原本单独输入的script命令行编程source命令的参数,就可轻易解决前面的问题。



exec也是让脚本在同一个进程执行,但是原有进程则被结束了

原有进程是否终止,就是exec与source/fork的最大差异



七、()与{}差别

1、有时候,需要在一定条件下一次执行多个命令;

()与{}这两对符号,虽然两者都可将多个命令做群组处理,但是技术细节是不一样的:

(   ):将包含的命令置于sub-shell去执行,也成为nested sub-shell

{    }:则是在同一个shell内完成,也成为non-named  command  group


要是在command  group中扯上变量及其他环境的修改,就可以根据不同的需求来使用()或者{}

通常,若所做的修改时临时的,且不想影响原有或以后的设定,那就是用();反之,则使用{}



八、$(())与$()还有${}差别在哪

1、$()与``(反引号)都是用来做命令替换的,所谓命令替换就是完成引号里的命令行,然后将其结果替换出来,再重组命令行

hangma@ubuntu:/home$ echo the process work dir is $(echo $PWD)
the process work dir is /home


hangma@ubuntu:/home$ echo the last sunday is $(date -d "last sunday" +%Y-%m-%d)
the last sunday is 2013-08-18


在多层次的复合替换中,``需要额外的转义(\`)处理,而$()则比较直观:

command1 `command2`command3``

原本的意图是要先将command3替换出来给command2处理,再将结果传给command1`command2...`来处理

而,真正的结果是在命令行中确实分成了`command2`与``两段;

正确的输入应该是:

command1`command2\`command3\``

但是换成$()就没问题了:

command1$(command2$(command3))



2、${}其实就是用来做变量替换用的;

一般情况下,$var与${var}并没有啥不一样的,但是用${}会比精确的界定变量名称的范围:

hangma@ubuntu:/home$ a=b
hangma@ubuntu:/home$ echo $ab


hangma@ubuntu:/home$ echo ${a}b
bb



${}可以用来分别替换获得不同的值:

假定URL="www.google.cn"

echo  ${URL%.*}           移除.*所匹配的最右边的内容

www.google

echo  ${URL%%.*}       将从最右边开始一直匹配到最左边的.*移除(贪婪操作符)

www

echo ${URL#*.}             移除*.所匹配的最左边的内容

google.cn

echo ${URL##*.}           将从最左边开始一直匹配到最右边的*.移除(贪婪操作符)

cn


hangma@ubuntu:/home$ URL="www.google.com"
hangma@ubuntu:/home$ echo ${URL%.*}
www.google
hangma@ubuntu:/home$ echo ${URL%%.*}
www
hangma@ubuntu:/home$ echo ${URL%o*}
www.google.c
hangma@ubuntu:/home$ echo ${URL%%o*}
www.g
hangma@ubuntu:/home$ echo ${URL#o*}
www.google.com
hangma@ubuntu:/home$ echo ${URL#*o}
ogle.com
hangma@ubuntu:/home$ echo ${URL##*o}
m



先设定file变量如下:

hangma@ubuntu:/home$ file=/path1/dir2/dir3/myfile.txt


${file:0:5}                                    提取最左边的5个字节

${file:5:5}                                    提取第5个字节右边的连续5个字节


hangma@ubuntu:/home$ echo ${file:0:5}                                    提取最左边的5个字节
/path
hangma@ubuntu:/home$ echo ${file:5:5}                                    提取第5个字节右边的连续5个字节

1/dir



${file/dir/path}                              将第一个dir替换为path

${file//dir/path}                              将全部dir替换为path

hangma@ubuntu:/home$ echo ${file/dir/path}
/path1/path2/dir3/myfile.txt
hangma@ubuntu:/home$ echo ${file//dir/path}
/path1/path2/path3/myfile.txt



${#var}:计算变量var的长度





3、数组定义

A="DJFKSFJ dsjfkjd“是定义A为一个字符串

若是想定义一个数组A,则需要:

A=(s d g k l l h j m d)


例子

hangma@ubuntu:/home$ a={1 2 3 4 5 6}                       如果使用花括号定义数组就是错误的
2: command not found
hangma@ubuntu:/home$ a=(1 2 3 4 5 6)

hangma@ubuntu:/home$ a=1

hangma@ubuntu:/home$ echo $a[1]                              如果不适用花括号界定变量界限,就会输出错误
1[1]
hangma@ubuntu:/home$ echo $a                       
1
hangma@ubuntu:/home$ echo ${a[1]}
2

hangma@ubuntu:/home$ echo ${a[@]}
1 2 3 4 5 6
hangma@ubuntu:/home$ echo ${a[*]}
1 2 3 4 5 6


${a[@]}:输出数组a的所有变量

${a[*]}:输出数组a的所有变量

${#a[@]}:输出数组a的长度

${#a[1]}:输出a[1]的长度


hangma@ubuntu:/home$ a=(sjdkfljdsk sjdkfj    sjdkfjdskl sjdkjfl)
hangma@ubuntu:/home$ echo ${#a[@]}
4
hangma@ubuntu:/home$ echo ${#a[1]}
6



4、$(()):用途是用来做整数运算的

符号有:+   -    *   /     %    &    |     ^    !




九、$@与$*差别在哪

$0代表脚本名称本身,而$1代表其后的第一个参数,$2,$3依次类推


$#代表脚本参数的个数,但是不包括脚本名称本身,就是说如果你没有给脚本传递参数,那么$#就是0



$#  与 $*的区别

两者只有在soft quote中才有差异,否则,都表示全部参数(不包括脚本名称本身)

”$@“扩展成”$1"  "$2"  "$3"

"$*"扩展成 “$1c$2c$3",其中c是IFS的第一个字符


"$@”用的最多,因为“$*"将所有字符串扩展成单个字符串,所以很少用。


#!/bin/bash
my_fun(){
echo "$#"
}
echo the num of para '"$@"' is $(my_fun "$@")
echo the num of para '"$*"' is $(my_fun "$*")



hangma@ubuntu:/home/ddddd/shelltest$ ./para.sh p1 "p2  p3"  p4
the num of para "$@" is 3
the num of para "$*" is 1








十、&& 与 ||

1、test的表示式称为expression,其命令格式有两种:

test  expression

或者

[  expression  ]

请务必注意[]之间的空格键



test目前支持的测试对象只有三种:

string:字符串,也就是纯文字

integer:整数(0或者正整数、不含负数或小数点)

file:文件


2、字符串比较:

字符串比较最好用双中括号,因为有时候采用单中括号会产生错误,所以最好避开他们:


[[  $str1 == $str2 ]]:当str1等于str2,返回真

[[  $str1 != $str2 ]]:如果不相同,返回真

[[  $str1 >  $str2 ]]:当str1大于str2,返回真

[[  $str1 <  $str2 ]]:当str1小于str2,返回真

[[   -z   $str ]]:当str包含的是空字符串,返回真

[[   -n   $str ]]:当str包含的不是是空字符串,返回真



3、文件测试

(1)文件或者目录是否存在的判断

[    -f         $var   ]:如果变量包含正常的文件路径或文件名,则返回真

[    -d        $var   ]:如果变量包含的是目录,则返回真

[    -e        $var   ]:如果变量包含的文件存在,则返回真

(2)文件读写执行操作权限的判断

[    -r        $var   ]:如果变量包含的文件可以读,则返回真

[    -w       $var   ]:如果变量包含的文件可以写,则返回真

[    -x        $var   ]:如果变量包含的文件可以执行,则返回真

(3)文件类型判断

[    -c        $var   ]:如果变量包含的是一个字符设备文件的路径,则返回真

[    -b        $var   ]:如果变量包含的是一个块设备文件的路径,则返回真

[    -L        $var   ]:如果变量包含的是一个符号链接,则返回真



4、算术比较

-gt:大于

-lt:小于

-ge:大于或等于

-le:小于或等于




注:假如在test中碰到变量替换,使用双引号引用是最保险的。



5、&& 和||是用来组建多个command  line用的:

command1   &&  command2:command2只有在command1为真时,才执行

command1   ||  command2:command2只有在command1为假时,才执行




十一、

1、*:匹配0个或者多个字符

      ?:匹配任意单一字符

[list]:匹配list中的任意单一字符

[!list]:匹配不在list中的任意单一字符

{str1,str2,str3...............}:匹配str1、str2、str3、、、、其一字符串

注:list可以为指定的个别字符,如abcd;也可以为一段ASCII字符的起止范围,如a-d


2、a*b:a与b之间可以有任意长度的字符,也可以一个没有

      a?b:a与b之间必须也只能有一个字符,可以是任意字符,如:aab,abb,acb,a0b等

      a[xyz]:a与b之间必须也只能有一个字符,但只能是x或y或z,如:axb,ayb,azb这三个

      a[!0-9]:a与b之间必须也只能有一个字符,但不能是阿拉伯数字,如axb,aab,a-b等

      a{abc,xyz,123}b:a与b之间只能是abc或xyz或123这三个字符串之一,如aabcb,axyzb,a123b这三个


注:(1)[!]中的!只有放在第一顺位时,才有排除之功,举例说:[!a]*表示当前目录下所有不以a开首的路径名称

                  /tmp/[a\!]*表示/tmp目录下以a或!开首的路径名称

         (2)[  -  ]中的-左右两边均有字符时,才表示一段范围,否则仅作“-”字符处理

                  /tmp/*[-z]/[a-zA-Z]*表示/tmp目录下所有以z或-结尾的子目录下以英文字母(不分大小写)开首的路径名称



字符组合:char  set

所谓的字符组合就是将多个连续的字符做一个集合:

abc:表示abc三个连续的字符,但彼此独立而非集合,可视为三个字符组合

(abc):表示abc这三个连续字符的集合,可视为一个字符组合

abc|xyz:表示abc或者xyz这两个字符组合之一

[abc]:表示单一字符,可为a或b或c

[^abc]:表示单一字符,不为a或b或c即可


锚点:用以标识句子中的位置所在:

^:表示句首,例如^abc表示以abc开首的句子

$:表示句尾,如abc$表示以abc为结尾的句子

\<:表示词首,\<abc表示以abc开始的词

\>:表示词尾,如abc\>表示以abc结尾的词



修饰符:

*:表示出现0到多个

{n}:表示前一个字符组合出现次数必须为n次

{n,}:表示前一个字符组合出现次数至少为n次

{n,m}表示a与c之间有n到m个存在





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值