@进程中的FORK
------------- sub shell
------------- primary shell -------------sub shell
FORK -------------- -------------sub shell
--------------
@EXPORT@
能将变量export在当前运行的脚本的所有的子进程.
不能将变量export到父进程(就是调用这个脚本或shell的进程)中.
@exec命令@
这个shell内建命令将使用一个特定的命令来取代当前进程.一般的当shell遇到一个命令,它会fork off一个子进程来真正的运行命令.使用exec内建命令,shell就不会fork了,并且命令的执行将会替换掉当前shell.因此,当我们在脚本中使用它时,当命令实行完毕,它就会强制退出脚本.
@SHELL命令执行的两种方式@
有两种方法执行shell scripts,一种是新产生一个shell,然后执行相应的shell scripts;一种是在当前shell下执行,不再启用其他shell。
新产生一个shell然后再执行scripts的方法是在scripts文件开头加入以下语句
#!/bin/sh
一般的script文件(.sh)即是这种用法。这种方法先启用新的sub-shell(新的子进程),然后在其下执行命令。
另外一种方法就是上面说过的source命令,不再产生新的shell,而在当前shell下执行一切命令。
source:
source命令即点(.)命令。
在bash下输入man source,找到source命令解释处,可以看到解释"Read and execute commandsfrom filename in the current shell environment and ..."。从中可以知道,source命令是在当前进程中执行参数文件中的各个命令,而不是另起子进程(或sub-shell)。source filename or .filename 执行filename中的命令。
exec:
在bash下输入man exec,找到exec命令解释处,可以看到有"No new process iscreated."这样的解释,这就是说exec命令不产生新的子进程。那么exec与source的区别是什么呢?
@exec的两种使用方式@
方式一
exec program
将 program 程序替代当前程序进程.
这就意味着 exec 后面再跟任何命令都是没有意义的, 因为他们永远得不到执行
方式二
可以用 exec 命令来关闭标准输入, 然后再以任何从中读取的文件重新打开
要把标准输入改变到文件, 用以下的格式的exec命令 exec < file
以后任何从标准输入读数据的命令都会从file中读取
如果用 exec 重新分配了标准输入, 后来又想重新分配到别处, 只需要再执行一次 exec.
如果要把标准输入重新改回终端, 可以写
exec < /dev/tty
以上讨论的内容也适用于重新分配标准输出. exec > report 将此后所有写向标准输出的文件写入report文件.
注: 这里的 exec 不是像前面介绍的那样用来启动运行新程序的, 而是用来重新分配标准输入和标准输出的.
@什么是标准输入标准输出?@
在BASH中,关于输入输出的重定向是这样的:
字符 行动
> 重定向标准输出
2> 重定向标准错误
2>&1 标准错误重定向到标准输出
< 重定向标准输入
| 重定向到下一个管道
>> 附加到标准输出
2>&1| 管标准输出和标准错误到另一个命令
@重定向@
例1
exec 2>$OUTPUT_PATH/$DATE/err_${TIME}.log
将错误日志重定向到err_${TIME}.log文件中。
exec 2>&1 1>$OUTPUT_PATH/$DATE/err_${TIME}.log可以使得stderr和stdout内容都被重定向,
例2观察crotab中使用的重定向
[@administer realtime_duplicate]#crontab -l
49 * * * * /usr/sbin/ntpdatentp.sohu.com > /dev/null 2>&1
49 16 * * * /sbin/clock -w
# [system] disk check
00 * * * * cd/root/machine_config/;sh super_check.sh -d disk.conf 1>output.log
[@administerorin_realtime_duplicate]#
程序运行中,默认的输出信息放入1中,错误信息放入2中。默认1和2的信息都显示到屏幕中。
但是可以使用>将它们重定向。
例2
[@administer ~]# (echo 123|cat>&2; echo 456) 1>/dev/null
123
[@administer ~]# (echo 123|cat>&2; echo 456) 2>/dev/null
456
@管道改变中的效率问题
在 cm1 | cm2 | cm3 ... 這段 pipe line 中,若要將 cm2 的結果存到某一檔案呢?
若你寫成 cm1 | cm2 > file | cm3 的話,
那你肯定會發現 cm3 的 stdin 是空的﹗(當然啦,你都將水管接到別的水池了﹗)
聰明的你或許會如此解決:
cm1 | cm2 > file ; cm3 <file
是的,你的確可以這樣做,但最大的壞處是:這樣一來,file I/O 會變雙倍﹗
在 command 執行的整個過程中,file I/O 是最常見的最大效能殺手。
凡是有經驗的 shell 操作者,都會盡量避免或降低 file I/O 的頻率。
所謂 tee 命令是在不影響原本 I/O 的情況下,將 stdout 複製一份到檔案去。
因此,上面的命令行可以如此打:
cm1 | cm2 | tee file | cm3
@解释语言与编译性语言@
计算机不能直接理解高级语言,只能直接理解机器语言,所以必须要把高级语言翻译成机器语言,计算机才能值型高级语言编写的程序。
翻译的方式有两种,一个是编译,一个是解释。两种方式只是翻译的时间不同。编译型语言写的程序执行之前,需要一个专门的编译过程,把程序编译成为机器语言的文件,比如exe文件,以后要运行的话就不用重新翻译了,直接使用编译的结果就行了(exe文件),因为翻译只做了一次,运行时不需要翻译,所以编译型语言的程序执行效率高。
解释则不同,解释性语言的程序不需要编译,省了道工序,解释性语言在运行程序的时候才翻译,比如解释性basic语言,专门有一个解释器能够直接执行basic程序,每个语句都是执行的时候才翻译。这样解释性语言每执行一次就要翻译一次,效率比较低。
@什么是脚本语言@
1 脚本语言是一种解释性的语言,例如vbscript,javascript,installshield script等等,它不像c/c++等可以编译成二进制代码,以可执行文件的形式存在. 脚本语言不需要编译,可以直接用,由解释器来负责解释。
@正则注意事项@
须留心 UNIX Shell中使用 "*"表示 Wild card,可用以代表任意长度的字
串.而 Regexp中使用 "."来代表一个任意字符.(注意:并非任意长度的字
串)Regexp中 "*"另有其它涵意, 并不代表任意长度的字串.
@解决mkdir问题@
create a directory, you need to have bothwrite (w) AND execute (x) permissions in the parent directory. Whereever youare, you can check the parent using "ls -l .."
所以,应该改变文件夹或者文件的属主
@脚本框架@
在总控文件run_all中,一方面可以export常量,另一方面可以运行子文件
@一些特殊的变量@
$0是该bash文件名
$? 是上一指令的返回值
$# 是参数的个数
$1 是运行shell脚步时提供的第一个参数
$2 是运行shell脚步时提供的第二个参数
$* 是调用当前脚本时的所有参数
$@ 基本上与上面相同。只不过是$*返回的是一个字符串,字符串中存在空格,但是$@返回多个字符串。
@反引号@
反引号 `
反引号(`)这个字符所对应的键一般位于键盘的左上角,不要将其同单引号(’)混淆。反引号括起来的字符串被shell解释为命令行,在执行时,shell首先执行该命令行,并以它的标准输出结果取代整个反引号(包括两个反引号)部分。例如:
$ pwd
/home/xyz
$ string="current directoryis `pwd`"
$ echo $string
current directour is /home/xyz
shell执行echo命令时,首先执行`pwd`中的命令pwd,并将输出结果/home/xyz取代`pwd`这部分,最后输出替换后的整个结果。
利用反引号的这种功能可以进行命令置换,即把反引号括起来的执行结果赋值给指定变量。例如:
$ today=`date`
$ echo Today is $today
Today is Mon Apr 15 16:20:13 CST1999
@数组操作
a=(abcdef)
[@administerExec2Source]# echo${a[@]}
#打印数组所有内容
abcdef
[@administerExec2Source]# echo ${a[1]}
#打印数组第二个元素
def
[@administerExec2Source]# echo ${a[0]}
#打印数组第一个元素
abc
[@administerExec2Source]# echo ${#a[1]}
#打印数组第一个元素的长度
3
@SHELL的返回值@
返回结果为0表示真,其它任何值为假。