SHELL十三问要点总结

1、shell 会依据 IFS(Internal Field Seperator) 将 command line 所输入的文字给拆解为"字段"(word)。然后再针对特殊字符(meta)先作处理,最后再重组整行 command line。
其中的 IFS 是 shell 预设使用的字段分隔符,可以由一个及多个如下按键组成: 
* 空格键(White Space) 
* 表格键(Tab) 
* 回车键(Enter) 

系统可接受的命令名称(command-name)可以从如下途径获得: 
* 明确路径所指定的外部命令 
* 命令别名(alias) 
* 自定功能(function) 
* shell 内建命令(built-in) 
* $PATH 之下的外部命令
 
2、" "(双引号) 与 ' '(单引号)差在哪?
command line 的每一个 charactor ,分为如下两种: 
* literal:也就是普通纯文字,对 shell 来说没特殊功能。 
* meta:对 shell 来说,具有特定功能的特殊保留字符。 

假如我们需要在 command line 中将这些保留字符的功能关闭的话,就需要 quoting 处理了。 
在 bash 中,常用的 quoting 有如下三种方法: 
* hard quote:' ' (单引号),凡在 hard quote 中的所有 meta 均被关闭。 
* soft quote: " " (双引号),在 soft quoe 中大部份 meta 都会被关闭,但某些则保留(如 $ )。
* escape : \ (反斜线),只有紧接在 escape (跳脱字符)之后的单一 meta 才被关闭。 

3、ENTER键不等于CR
代码: 
   $ A='B 
   > C 
   > ' 
   $ echo $A 
   B 
   C  

由于 <enter> 被置于 hard quote 当中,因此不再作为 CR 字符来处理。 这里的 <enter> 单纯只是一个断行符号(new-line)而已,由于 command line 并没得到 CR 字符, 
因此进入第二个 shell prompt (PS2,以 > 符号表示),command line 并不会结束, 直到第三行,我们输入的 <enter> 并不在 hard quote 里面,因此并没被关闭, 此时,command line 碰到 CR 字符,于是结束、交给 shell 来处理。 同样的道理反斜线也会起到同样的作用:
代码: 
   $ A=B\ 
   > C\ 
   > 
   $ echo $A 
   B 
   C  

4、在 awk 或 sed 的命令参数中调用之前设定的一些变量时,为何不能?
要解决这些问题,关键点就是: 
* 区分出 shell meta 与 command meta 
前面我们提到的那些 meta ,都是在 command line 中有特殊用途的,比方说 { } 是将其内一系列 command line 置于不具名的函式中执行(可简单视为 command block ), 但是,awk 却需要用 { } 来区分出 awk 的命令区段(BEGIN, MAIN, END)。 若你在 command line 中如此输入: 
代码: 
$ awk {print $0} 1.txt  
由于 { } 在 shell 中并没关闭,那 shell 就将 {print $0} 视为 command block , 
但同时又没有" ; "符号作命令区隔,因此就出现 awk 的语法错误结果。 
要解决之,可用 hard quote : 
代码: 
$ awk '{print $0}' 1.txt  
上面的 hard quote 应好理解,就是将原本的{、<space>、$(注三)、}这几个shell meta 关闭, 避免掉在 shell 中遭到处理,而完整的成为 awk 参数中的 command meta。(注三:而其中的 $0 是 awk 内建的 field number,而非 awk 的变量,awk 自身的变量无需使用$。) 要是理解了 hard quote 的功能,再来理解 soft quote 与 escape 就不难: 
代码: 
awk "{print \$0}" 1.txt 
awk \{print\ \$0\} 1.txt  
然而,若你要改变 awk 的 $0 的 0 值是从另一个 shell 变量读进呢? 比方说:已有变量 $A 的值是 0 ,那如何在 command line 中解决 awk 的 $$A 呢? 
代码:  
A=0 
awk "{print \$$A}" 1.txt 
awk \{print\ \$$A\} 1.txt 
awk '{print $'$A'}' 1.txt 
awk '{print $'"$A"'}' 1.txt     # 注:"$A" 包在 soft quote 中  

4、变量替换与command line
代码: 
   $ A=ls 
   $ B=la 
   $ C=/tmp 
   $ $A -$B $C  
必需强调的是,我们所提的变量替换,只发生在 command line 上面。(是的,让我们再回到 command line 吧﹗) 仔细分析最后那行 command line ,不难发现在被执行之前(在输入 CR 字符之前), 
$ 符号会对每一个变量作替换处理(将变量值替换出来再重组命令行),最后会得出如下命令行: 
代码: 
   ls -la /tmp  
若从技术细节来看,shell 会依据 IFS(Internal Field Seperator) 将 command line 所输入的文字给拆解为"字段"(word)。 然后再针对特殊字符(meta)先作处理,最后再重组整行 command line。 这里的 $ 就是 command line 中最经典的 meta 之一了,就是作变量替换的。

5、exec跟source 差在哪?  
提问:
cd /etc/aa/bb/cc可以执行 
但是把这条命令写入shell时shell不执行! 
这是什幺原因呀! 
让我们回到上一章所谈到的"环境变量"吧: 
* 所谓环境变量其实就是那些会传给子进程的变量。简单而言,"遗传性"就是区分本地变量与环境变量的决定性指针。
然而,从遗传的角度来看,我们也不难发现环境变量的另一个重要特征: 
* 环境变量只能从父行程到子行程单向继承。换句话说:在子行程中的环境如何变更,均不会影响父行程的环境。
正常来说,当我们执行一个 shell script 时,其实是先产生一个sub-shell的子行程,然后sub-shell 再去产生命令行的子行程。因为,一般我们跑的 shell script 是用subshell去执行的。 
从 process 的观念来看,是 parent process 产生一个 child process 去执行,当 child 结束后,会返回 parent ,但 parent 的环境是不会因 child 的改变而改变的。所谓的环境元数很多,凡举 effective id, variable, workding dir 等等... 
* 所谓 source 就是让 script 在当前 shell 内执行、而不是产生一个 sub-shell 来执行。 由于所有执行结果均于当前 shell 内完成,若 script 的环境有所改变,当然也会改变当前环境了。
因此,只要我们要将原本单独输入的 script 命令行变成 source 命令的参数,就可轻易解决前例提到的问题了。
代码: 
source ./my.script
或: 
. ./my.script  
* exec 也是让 script 在同一个行程上执行,但是原有行程则被结束了。 
也就是简而言之:原有行程会否终止,就是 exec 与 source/fork 的最大差异了。 

6、( )与{ }差在哪? 
在 shell command line 中,一般人或许不太计较 ( ) 与 { } 这两对符号的差异, 
虽然两者都可将多个命令作群组化处理,但若从技术细节上,却是很不一样的: 
( ) 将 command group 置于 sub-shell 去执行,也称 nested sub-shell。 
{ } 则是在同一个 shell 内完成,也称为 non-named command group。 
要是在 command group 中扯上变量及其它环境的修改,我们可以根据不同的需求来使用 ( ) 或 { }。 通常而言,若所作的修改是临时的,且不想影响原有或以后的设定,那我们就 nested sub-shell,反之,则用 non-named command group 。

7、$(( )) 与 $( ) 还有${ } 差在哪? 
在 bash shell 中,$( ) 与 ` ` (反引号) 都是用来做命令替换用(command substitution)的。所谓的命令替换与我们第五章学过的变量替换差不多,都是用来重组命令行: 
* 完成引号里的命令行,然后将其结果替换出来,再重组命令行。 
接下来,再让我们看 ${ } 吧... 它其实就是用来作变量替换用的啦。 一般情况下,$var 与 ${var} 并没有啥不一样。但是用 ${ } 会比较精确的界定变量名称的范围,比方说: 
代码: 
$ A=B 
$ echo $AB  
可以用 ${ }分别替换获得不同的值: 
代码:
${file#*/}:拿掉第一条 / 及其左边的字符串:dir1/dir2/dir3/my.file.txt 
${file:0:5}:提取最左边的 5 个字节:/dir1 
也可以对变量值里的字符串作替换: 
代码:
${file/dir/path}:将第一个 dir 提换为 path:/path1/dir2/dir3/my.file.txt 
${file//dir/path}:将全部 dir 提换为 path:/path1/path2/path3/my.file.txt 
利用 ${ }还可针对不同的变量状态赋值(没设定、空值、非空值): 
代码:
${file-my.file.txt} :假如 $file 为空值,则使用 my.file.txt 作默认值。(保留没设定及非空值) 
还有哦,${#var} 可计算出变量值的长度: 
代码:
${#file} 可得到 27 ,因为 /dir1/dir2/dir3/my.file.txt 刚好是 27 个字节... 
最后为大家介绍 $(( )) 的用途吧:它是用来作整数运算的。 
在 bash 中,$(( )) 的整数运算符号大致有这些: 
+ - * / :分别为 "加、减、乘、除"。 
% :余数运算 
& | ^ !:分别为 "AND、OR、XOR、NOT" 运算。 

8、[^ ]跟[! ]差在哪?
这道题目说穿了,就是要探讨Wildcard与Regular Expression的差别的。
让我 们来看看wildcard是什么回事吧。
Part-I: 
Wildcard 首先, wildcard也是属于command line的处理工序,作用于argument里的path之上. 没错,它不用在command_name也不用在options上. 而且,若argument不是path的话,那也与wildcard无关. 换句更为精确的定义来讲, wildcard是一种命令行的路径扩展(path expansion)功能. 提到这个扩展,那就不要忘记了command line的"重组"特性了! 是的,这与变量替换(variable substitution)及命令替换(command substitution)的重组特性是一样的! 也就是在wildcard进行扩展后,命令行会先完成重组才会交给shell来处理.
Part-II: 
Regular Expression

9、eval的作用?
再一次替换重组
a=1
A1=abc
我们都知道echo $A1就可得到abc这个結果.
然而, 我们能否用$A$a來取代$A1而同样替换出abc呢?
这个问题我们可以轻松的用eval来解決:
eval echo \$A$a

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值