Showing posts with label Programming. Show all posts
Showing posts with label Programming. Show all posts

Sunday, August 23, 2009

Unix 哲学基础[Unix编程艺术读书笔记]

1、让每个程序就做好一件事。如果有新任务,就重新开始,不要往原程序中加入新功能而搞得复杂。
2、假定每个程序的输出都会成为另一个程序的输入,哪怕那个程序还是未知的。输出中不要有无关的信息干扰。避免使用二进格式输入,而是坚持使用文本流,不要坚持使用交互式输入。
3、尽可能早地将设计和编译的软件投入使用,对于拙劣的代码别犹豫,扔掉重写。
4、优先使用工具减轻编程任务,工欲善其事,必先利其器。
5、花哨的算法复杂度大,并比简单的算法更容易出bug,更难实现,理解和维护。尽量使用简单的算法配合简单的数据结构。
6、编程的核心是数据结构,而不是算法。
7、不确定的时候就用穷举。
8、小就是美,在确保任务完成的基础上,程序功能尽可能少。

Unix 原则
1、模块原则:使用简洁的接口拼合拼合简单的部件。
2、清晰原则:清晰胜于机巧。
3、组合原则:设计时考虑拼接组合。
4、分离原则:策略同机制分离,接口同引擎分离。
5、简洁原则:设计要简洁,复杂度能低则低。
6、吝啬原则:不要编写庞大的程序。
7、透明性原则:设计要可见,以便审查和调试。
8、健壮原则:健壮源于透明和简洁。
9、表示原则:要求逻辑质朴而健壮。
10、通俗原则:即最小惊异原则,接口设计避免标新立异。
11、缄默原则:如果一个程序没什么好说的,就沉默。
12:补救原则:出现异常时要给出足够的错误信息。
13、经济原则:宁花机器一分钟,不花程序员一分钟。
14、生成原则:避免手工hack,尽量编写程序去生成程序。
15、优化原则:原型设计,先求运行,再求正确,最后求快。
16、多样原则:决不相信所谓“不二法门”的断言。
17、扩展原则:设计着眼未来,未来总比预想来得快。

Unix 哲学之总结
所有Unix的哲学用一句话来概括就是“KISS”原则:
Keep It Simple, Stupid!

Thursday, September 20, 2007

The Elements of JavaScript Style (Part One)

Part One


Douglas Crockford

The Department of Style


2005-09-19


Programming is difficult. At its core, it is about managing complexity. Computer
programs are the most complex things that humans make. Quality is a illusive
and elusive.


Good architecture is necessary to give programs enough structure to be able to grow
large without collapsing into a puddle of confusion, but the ways in which we
express the details of a program are equally important. A program's true nature
can be concealed by sloppy coding. Only when the presentation of a program is
clear can we have any hope of reasoning correctly about its efficiency, or security,
or correctness.


The classic work in literary style is William Strunk's The
Elements of Style
, a skinny manual on writing in English, with advice on
usage, composition, and form. The idea of style was applied unsuccessfully to
programming in Kreitzberg and Shneiderman's The
Elements of FORTRAN Style
in 1972, and then brilliantly in Kernighan and
Plauger's The Elements of Programming Style in 1978:




Good programming cannot be taught by preaching generalities. The way to learn
to program well is by seeing, over and over, how real programs can be improved
by the application of a few principles of good practice and a little common
sense.



They took programs culled from other programming textbooks, which they criticized
and improved.


When we talk of style here, we are not talking about fads and fashions,
nor are we talking about CSS or conventions of layout or typography. We are
talking about timeless qualities of expression which can substantially increase
the value of a codebase. For companies whose valuations are are inextricably
bound to their codebases, style should be a vital concern.


We use many programming languages, but in a way, JavaScript is the most important.
It is the language of the browser. When people come to our site, they are (perhaps
unknowingly) inviting our JavaScript programs to execute in their machines.
We have a special obligation to make those programs good.


There are no good texts on JavaScript
programming. Most of the people on the web who are producing JavaScript programs
learned it by copying really bad examples from bad books, bad websites, and
bad tools. We have
an amazingly good community of JavaScript programmers here, but still we can
benefit from better practice of style.



To demonstrate this, I will be taking programs from our public website, and
showing how they can be improved. It is not my intention to embarrass anyone.
My intention is only to show the value of style by example. I will be revealing
no secrets: I will be showing you what we are already transmitting to everyone
in the world.


 


The following examples were extracted from www.yahoo.com
on 2005-09-19.


<script language=javascript><!--
lck='',
sss=1127143538,
ylp='p.gif?t=1127143538&_ylp=A0Je5ipy2C5D54AAwVX1cSkA',
_lcs='';
--></script>

This script block uses the language attribute. This was a feature
that was introduced by Microsoft in order to support VBScript. Netscape then
adopted it to support its own nonstandard deviations. W3C did not adopt the
language attribute, favoring instead a type attribute
which takes a MIME type. Unfortunately, the MIME type was not standardized,
so it is sometimes "text/javascript" or "application/ecmascript"
or something else. Fortunately, all browsers will always choose JavaScript as
the default programming language, so it is always best to simply write <script>.
It is smallest, and it works on the most browsers.



The use of HTML comments in scripts dates further back to a transitional problem
between Netscape Navigator and Netscape Navigator 2. The latter introduced the
<script> tag. However, users of the former would see the
script as text because of the HTML convention that unrecognized markup is ignored.
The <!-- comment hack stopped being necessary by the time Netscape
Navigator 3 came out. It certainly is not needed now. It is ugly and a waste
of space.


The comma operator was borrowed, like much of JavaScript's syntax, from C.
The comma operator takes two values and returns the second one. Its presence
in the language definition tends to mask certain coding errors, so compilers
tend to be blind to some mistakes. It is best to avoid the comma operator, and
use the semicolon statement separator instead.


In this case, we are defining some global variables. JavaScript, when assigning
to an unknown variable, creates a new global variable instead of generating
an error. This was, in hindsight, a mistake. It is best to avoid mistakes, even
when they are standard mistakes. We should be explicit in declaring the variables.
It will cost us 4 characters, but it is the right thing to do.



<script>

var lck = '3ek6b0i2he2a5eh3/o',
sss = 1126894256,
ylp = 'p.gif?t=1126894256&_ylp=A0Je5iOwCitDw2YBX331cSkA',
_lcs = '94040';
</script>

From that we can derive this principle:




Avoid archaic constructions.




The next example looks at a cookie class constructor. It creates an object
having a get method and a set method.



function yg_cookie() {
this.get = function (n) {
var s,
e,
v = '',
c = ' ' + document.cookie + ';';
if ((s = c.indexOf((' ' + n + '='))) >= 0) {
if ((e = c.indexOf(';',s)) == -1)
e = c.length;
s += n.length + 2;
v = unescape(c.substring(s, e));
}
return (v);
}
this.set = function (n,v,e) {
document.cookie = n + "=" + escape(v) +
";expires=" + (new Date(e * 1000)).toGMTString() +
";path=/" + ";domain=www.yahoo.com";
}
}
var _yc = new yg_cookie();


JavaScript's if statement is similar to C's: it can take statements
or blocks. The problem with using statements is that a common error is very
difficult to detect. It is better to write


if ((e = c.indexOf(';', s)) == -1) 
e = c.length;

as


if ((e = c.indexOf(';', s)) == -1) {
e = c.length;
}

The use of blocks avoids situations like this:


if ((e = c.indexOf(';', s)) == -1) 
e = c.length;
s += n.length + 2;

It might appear that s is only incremented when indexOf
returns -1, but this is not the case. Bugs like that can be very
expensive to find, but can be inexpensively avoided by always using braces to
indicate structure.





Always use blocks in structured statements.




Another bad habit that JavaScript inherited from C is the assignment expression.
It appears to streamline code, but it can make control flow more difficult to
understand. The get method gets clearer if we separate the computation
of s and e from their uses.


this.get = function (n) {
var v = '',
c = ' ' + document.cookie + ';',
s = c.indexOf((' ' + n + '=')),
e = c.indexOf(';', s);
if (s >= 0) {
if (e == -1) {
e = c.length;
}
s += n.length + 2;
v = unescape(c.substring(s, e));
}
return (v);
}


We can now see that there are excess parens around the argument to indexOf
where s is computed. (There are also unnecessary parens in the
return statement.) But more importantly, it is easier to see what
the purpose of if (e == -1) is: If a final semicolon is not found
in the cookie, then assume that the cookie ends at the end of the string. However,
when we computed c, we appended a semicolon to the cookie, which
guarantees that the condition the if is anticipating will never
happen. So we can remove the if.





Avoid assignment expressions.




When a function is assigned to a value, as in this.get = function (n)
{
... } it should end with a semicolon just like all assignment
statements.


function yg_cookie() {
this.get = function (n) {
var v = '',
c = ' ' + document.cookie + ';',
s = c.indexOf((' ' + n + '='));
if (s >= 0) {
s += n.length + 2;
v = unescape(c.substring(s, c.indexOf(';', s)));
}
return v;
};
this.set = function (n,v,e) {
document.cookie = n + "=" + escape(v) +
";expires=" + (new Date(e * 1000)).toGMTString() +
";path=/" + ";domain=www.yahoo.com";
};
}
var _yc = new yg_cookie();


Finally, we see that yg_cookie is a constructor that produces
a single stateless object. We do not need a constructor function at all. We
can simply make an empty object and augment it by assigning the methods to it.


var _yc = new Object();
_yc.get = function (n) {
var v = '',
c = ' ' + document.cookie + ';',
s = c.indexOf((' ' + n + '='));
if (s >= 0) {
s += n.length + 2;
v = unescape(c.substring(s, c.indexOf(';', s)));
}
return v;
};
_yc.set = function (n,v,e) {
document.cookie = n + "=" + escape(v) +
";expires=" + (new Date(e * 1000)).toGMTString() +
";path=/" + ";domain=www.yahoo.com";
};


If we do not need to support Netscape 3 or IE 4, then we can do that more elegantly
by using the object literal notation.


var _yc = {
get: function (n) {
var v = '',
c = ' ' + document.cookie + ';',
s = c.indexOf((' ' + n + '='));
if (s >= 0) {
s += n.length + 2;
v = unescape(c.substring(s, c.indexOf(';', s)));
}
return v;
},
set: function (n,v,e) {
document.cookie = n + "=" + escape(v) +
";expires=" + (new Date(e * 1000)).toGMTString() +
";path=/" + ";domain=www.yahoo.com";
}
};




Use object augmentation.




At this point we have a couple of methods for manipulating cookies. It is surprising
then that the very next thing we find is code that does cookie manipulation
without taking advantage of the methods we just defined.


var b,
l = '',
n = '0',
y;
y = ' ' + document.cookie + ';';
if ((b = y.indexOf(' Y=v')) >= 0) {
y = y.substring(b, y.indexOf(';', b)) + '&';
if ((b = y.indexOf('l=')) >= 0) {
l = y.substring(b + 2, y.indexOf('&', b));
if ((b = y.indexOf('n=')) >= 0)
n = y.substring(b + 2, y.indexOf('&', b));
}
}


It even replicates the same techniques that we saw earlier. It is likely that
both chunks of code were adapted from the same faulty original. We can improve
it by taking advantage of our recent work:


var l = '',
n = '0',
y = _yc.get('Y') + '&',
b = y.indexOf('l=');
if (b >= 0) {
l = y.substring(b + 2, y.indexOf('&', b));
b = y.indexOf('n=');
if (b >= 0) {
n = y.substring(b + 2, y.indexOf('&', b));
}
}

Code reuse is the Holy Grail of Software Engineering. We can imagine great
efficiencies obtained by avoiding the vast amount of hand work required by the
current state of the art. Here we found a failure to use a method that had been
defined adjacent to the place where it was needed.




Use common libraries.




The structure of software systems tend to reflect the structure of the organizations
that produce them. In this case, we see evidence of obvious inefficiencies caused
by an organization that lacks awareness of the interconnectedness of its own
processes. The application of style is critical, because it is only possible
to fit the pieces together properly if we can understand what the pieces are.


原文: The Elements of JavaScript Style

The Elements of JavaScript Style (Part Two)

Part Two: Idioms


Douglas Crockford

The Department of Style


2005-09-21


There are idioms that we can use to make our intentions clearer and more concise.


Consider this function:


function gw(f) {
if (d.w.sv.checked == true) {
zv = 'on';
} else {
zv = 'off';
}
procframe.location.replace("http://b.www.yahoo.com/module/wtr_tr.php?p=" +
escape(f.p.value) + "&sv=" + zv);
return false;
}

The == operator should not be used for comparing values with true
because it does type coercion. If our intent is to determine if d.w.sv.checked
is the boolean value true, then we must use the ===
operator. If we only care that a value is truthy (and not falsy)
then it is better to not use an equality operator at all.



For example, because of type coercion., 1 == true is true, but
1 === true
is false. The == operator can hide type errors.




Watch out for type coercion when using ==.





The if statement is being used to select one of two values. This
is what the ?: ternary operator is for.


zv = d.w.sv.checked ? 'on' : 'off';



Use the ?: operator to select one of two values.





The variable zv is not declared as a var or parameter of this
function, so it is an implicit global variable. If there is another function
on this page that uses a similarly named global variable, then a failure could
result. Bugs like this can be very difficult to find but are very easily avoided.
In this case, we can either declare that zv as a var, or we can
notice that it is used only once and get rid of it entirely.


function gw(f) {
procframe.location.replace("http://b.www.yahoo.com/module/wtr_tr.php?p=" +
escape(f.p.value) + "&sv=" + d.w.sv.checked ? 'on' : 'off');
return false;
}



Never use implicit global variables.





We would normally be suspicious of functions that return a constant, but this
is something that is sometimes required in a browser environment.



Next we see a case where the ?: operator is used improperly. It
is being used to select between two assignments.


function u(o, z) {
var em = o.id.substring(1);
var p = d.getElementById('e' + em);
if (p) {
(z == 0) ? p.style.backgroundColor = '#fff' :
p.style.backgroundColor = '#989898';
}
p = d.getElementById('e' + (em - 1));
if (p) {
(z == 0) ? p.style.backgroundColor = '#fff' :
p.style.backgroundColor = '#989898';
}
}

The test of z is ambiguous. Do we select color #fff
if z is exactly 0, or if z is falsy?
As stated it appears to indicate the former, but it actually means the latter.
Fortunately in this case, we probably intend the latter, so it is not technically
an error (this time). But it is bad stylistically.



We can replace the ?: with an if, but it happens
that the assignments all use the same lvalue, so this time we can make
the correction without using an if.


function u(o, z) {
var em = o.id.substring(1),
p = d.getElementById('e' + em);
if (p) {
p.style.backgroundColor = z ? '#fff' : '#989898';
}
p = d.getElementById('e' + (em - 1));
if (p) {
p.style.backgroundColor = z ? '#fff' : '#989898';
}
}




Do not use the ?: operator to select one of
two actions.




Event handling suffers from browser dependencies. Ideally, application programs
should be insulated from browser deficiencies by common libraries. When such
libraries are not available, functions like this happen:


function md(e) {
(window.event) ? ev = window.event : ev = e;
(ev.target) ? sr = ev.target : sr = ev.srcElement;
if (ev && sr && sr.id == "fp" || sr.id == "sb") st = 1;
if (sr.className.indexOf("pllist") < 0 && sr.className != "more" &&
sr.className != "plinkc" && sr.tagName != "scrollbar " &&
_toClose && _toCloseNorgie) {
d.getElementById(_toClose).innerHTML = "";
_toClose = "";
_toCloseNorgie.parentNode.className = '';
_toCloseNorgie = '';
}
}


Some browsers pass an event object to event handlers as a parameter. Microsoft
chose instead to put the event object in a global event variable.
In JavaScript, global variables are members of the global object. In browsers,
the global object always contains a window member whose value is
the global object. Accessing global variables through window is
a way of avoiding undefined variable errors when testing for the existence of
a variable. However, it should never be necessary to make such a test.


Instead of first determining if this is a Microsoft event, we can instead ask
if it is the other kind.


ev = e || event;

We used the || (default) operator. If e
is truthy, we will use its value, but if e is falsy then we will
use event.



In the next statement, we can again use the || operator to determine
sr, the source element or target.


We should make ev and sr vars to avoid global conflict.


function md(e) {
var ev = e || event,
sr = ev.target || ev.srcElement;
if (sr && (sr.id == 'fp' || sr.id == 'sb')) {
st = 1;
}
if (sr.className.indexOf('pllist') < 0 && sr.className != 'more' &&
sr.className != 'plinkc' && sr.tagName != 'scrollbar ' &&
_toClose && _toCloseNorgie) {
d.getElementById(_toClose).innerHTML = '';
_toClose = '';
_toCloseNorgie.parentNode.className = '';
_toCloseNorgie = '';
}
}




Use the || operator to specify a default value.




Next we find another event handler. As you would expect, it repeats some of
the same stylelessness as the previous one.


function kd(e) {
(window.event) ? ev = window.event : ev = e;
(ev.target) ? el = ev.target : el = ev.srcElement;
if (ev && el) {
code = ev.keyCode;
id = el.id;
} else {
return;
}
ctn = lt.id.substring(1);
if (code == 13) {
return;
} else if ((code == 191 || code == 222) && id != 'fp') {
_ffs = 1;
gk = 0;
} else if ((code < 31 || code > 41) &&
(code < 16 || code > 18) && code != 9 && code != 8) {
gk = 1;
} else {
gk = 0;
}
if (!_ffs && (id == 'fp' || id == 'st')) {
if (code == 9) {
if (box.value == '' || (box.value != '' && (at == 1 || ev.shiftKey))) {
mt(ctn);
} else if (id == 'st' && box.value != '' && at == 0) {
at = 1;
mt(ctn);
}
} else if (id == 'fp' && gk == 0 &&
(box.value == '' && st == 0) && !ev.shiftKey && !ev.ctrlKey && !ev.altKey) {
d.getElementById('mk').focus();
d.getElementById('mk').blur();
} else if (gk == 1) {
at = 0;
}
} else if ((id == 'mk2' && box.value != '' && ev.shiftKey && code == 9) ||
(id == 'm6' && !ev.shiftKey && code == 9)){
d.getElementById('mk').focus();
} else if (!_ffs && gk == 1 && el.type != 'text' && !ev.ctrlKey && !ev.altKey){
box.value = '';
box.focus();
}
}
function mt(ctn) {
if ((ev && !ev.ctrlKey && !ev.altKey) || !ev) {
if (ev.shiftKey){
nextTab = parseInt(ctn) - 1;
} else {
nextTab = parseInt(ctn) + 1;
}
if (nextTab == 0) {
d.getElementById('mk').focus();
} else if (nextTab < 8) {
t(d.getElementById('v' + nextTab));
} else {
return;
}
}
}


What is interesting is that it has a companion function, mt, which
is only called from kd. mt is passed one parameter
(ctn), but most of the communication between kd and
mt is through global variables.





Global variables are evil.




We could eliminate the use of global variables by increasing the number of
parameters sent to mt. But instead, we will make mt
an inner function of kd. As an inner function, mt
would have access to all of kd's vars.



function kd(e) {
var ev = e || event,
el = ev.target || ev.srcElement,
cnt,
code = ev.keyCode,
gk,
id = el.id,
ctn = lt.id.substring(1);

function mt() {
var nextTab;
if (!ev.ctrlKey && !ev.altKey) {
nextTab = parseInt(ctn) + ev.shiftKey ? -1 : 1;
if (!nextTab) {
d.getElementById('mk').focus();
} else if (nextTab < 8) {
t(d.getElementById('v' + nextTab));
}
}
}

if (code == 13) {
return;
} else if ((code == 191 || code == 222) && id != 'fp') {
_ffs = 1;
gk = 0;
} else if ((code < 31 || code > 41) &&
(code < 16 || code > 18) && code != 9 && code != 8) {
gk = 1;
} else {
gk = 0;
}
if (!_ffs && (id == 'fp' || id == 'st')) {
if (code == 9) {
if (box.value == '' ||
(box.value != '' && (at == 1 || ev.shiftKey))) {
mt();
} else if (id == 'st' && box.value != '' && at == 0) {
at = 1;
mt();
}
} else if (id == 'fp' && gk == 0 && (box.value == '' && st == 0) &&
!ev.shiftKey && !ev.ctrlKey && !ev.altKey) {
d.getElementById('mk').focus();
d.getElementById('mk').blur();
} else if (gk == 1) {
at = 0;
}
} else if ((id == 'mk2' && box.value != '' && ev.shiftKey && code == 9) ||
(id == 'm6' && !ev.shiftKey && code == 9)){
d.getElementById('mk').focus();
} else if (!_ffs && gk == 1 && el.type != 'text' && !ev.ctrlKey &&
!ev.altKey) {
box.value = '';
box.focus();
}
}


Function mt is called from two places in kd. By making
it an inner function, we were able to significantly reduce the number of global
variables that kd uses, which reduces its likelihood of interfering
with other components. kd is still a mess, but it is now a slightly
less disorderly mess.




Use inner functions to avoid global variables.


原文The Elements of JavaScript Style

Saturday, June 02, 2007

[转]Bash 编程

作者:jiupima(CU)
一. Bash特殊字符
1. 通配符:
*:匹配任何字符串
?:匹配任何单个字符
集合运算符:用一些单个字、一个连续范围或断续的字符集合作为通配符
[set]:用字符集合作通配符匹配单个字符,如:[aeiou],[a-o],[a-h, w-z]
[!set]:除了集合外的所有字符组成的集合作通配符
2. 花括号展开式(可以嵌套):
格式:[前导字符串]{字符串1[{嵌套字符串1…}] [, 字符传2…]}[后继字符串]
如:c{a{r, t, n}, b{r, t, n}}s 就等于 cars cats cans cbrs cbts cbns
3. 其它特殊字符:
< :输入重定向
> :输出重定向(没有文件则创建,有则覆盖)
>> :输出重定向(没有则创建,有则追加到文件尾部)
( :子shell开始,子shell继承父shell部分环境变量
) :子shell结束
{ :命令块开始,由当前shell执行,保留所有环境变量
} :命令块结束
| :管道
\ :引用后面的单个字符
‘ :强引用字符串,不解释特殊字符
“ :弱引用字符串,解释所有特殊字符
~ :根目录
` :命令替换
; :命令分隔符(命令终止符),运行在一行里执行多条命令
# :行注释
$ :变量表达式
& :在后台执行命令
* :字符串通配符
? :单个字符通配符

二. Bash变量
1. 自定义变量
用户自定义的变量由字母、数字和下划线组成,并且变量名的第一个字符不能为数字,且变量名大小写敏感。
varname=value 注意bash不能在等号两侧留空格
shell语言是非类型的解释型语言,给一个变量赋值实际上就是定义了变量,而且可以赋不同类型的值。引用变量有两种方式,$varname和${varname},为防止变量在字符串中产生歧义建议使用第二种方式,引用未定义的变量其值为空。
为一个变量赋值一个串,需要用到引号,注意`、’、”的不同,``相当于$()
为了使变量可以在其它进程中使用,需要将变量导出:export varname
2. 环境变量
可以用set命令给变量赋值或查看环境变量值,使用unset命令清除变量值,使用export导出变量将可以使其它进程访问到该环境变量。
3. 位置变量
位置变量对应于命令行参数,其中$0为脚本名称,$1为第一个参数,依次类推,参数超过9个必须使用${}引用变量。shell保留这些变量,不允许用户以另外的方式定义它们,传给脚本或函数的位置变量是局部和只读的,而其余变量为全局的(可以用local关键字声明为局部)。
4. 其它变量
$? :保存前一个命令的返回码
$- :在Shell启动或使用set命令时提供选项
$$ :当前shell的进程号
$! :上一个子进程的进程号
$# :传给脚本或函数的参数个数,即位置变量数减1,不含脚本名称。
$* :传给脚本或函数的参数组成的单个字符串,即除脚本名称后从第一个参数开始的字符串,每个参数以$IFS分隔(一般内部域分隔符$IFS为1空格)。形同”…”
$@ :传给脚本或函数的参数列表,这些参数被表示为多个字符串。形同”” “” “”…。$*和$@之间的不同方便使用两种方法处理命令行参数,但是在打印时参数外观没有区别。
如: #vi posparm.sh
function cutparm
{echo –e “inside cntparm: $# parms: $*\n”}
cntparm “$*”
cntparm “$@”
#./posparm.sh abc bca cab
inside cntparm: 1 parms: abc bca cab
inside cntparm: 3 parms: abc bca cab

三. Bash操作符
1. 字符串操作符(替换操作符)
${var:-word} 如果var存在且不为空,返回它的值,否则返回word
${var:=word} 如果var存在且不为空,返回它的值,否则将word赋给var, 返回它的值
${var:+word} 如果var存在且不为空,返回word,否则返回空
${var:?message} 如果var存在且不为空,返回它的值,
否则显示“bash2:$var:$message”,然后退出当前命令或脚本
${var:offset[:length]} 从offset位置开始返回var的一个长为length的子串,
若没有length,则默认到var串末尾
2. 模式匹配操作符
${var#pattern} 从var头部开始,删除和pattern匹配的最短模式串,然后返回 剩余串
${var##pattern} 从var头部开始,删除和pattern匹配的最长模式串,然后返回 剩余串,basename path=${path##*/}
${var%pattern} 从var尾部开始,删除和pattern匹配的最短模式串,然后返回 剩余串,dirname path=${path%/*}
${var%%pattern} 从var尾部开始,删除和pattern匹配的最长模式串,然后返回 剩余串
${var/pattern/string} 用string替换var中和pattern匹配的最长模式串

四. Shell中条件和test命令
Bash可以使用[ … ]结构或test命令测试复杂条件
格式:[ expression ] 或 test expression
返回一个代码,表明条件为真还是为假,返回0为真,否则为假。
注:左括号后和右括号前空格是必须的语法要求
1. 文件测试操作符
-d file file存在并且是一个目录
-e file file存在
-f file file存在并且是一个普通文件
-g file file存在并且是SGID(设置组ID)文件
-r file 对file有读权限
-s file file存在并且不为空
-u file file存在并且是SUID(设置用户ID)文件
-w file 对file有写权限
-x file 对file有执行权限,如果是目录则有查找权限
-O file 拥有file
-G file 测试是否是file所属组的一个成员
-L file file为符号链接
file1 –nt file2 file1比file2新
file1 –ot file2 file1比file2旧
2. 字符串操作符
str1=str2 str1和str2匹配
str1!=str2 str1和str2不匹配
str1<str2 str1小于str2
str1>str2 str1大于str2
-n str str的长度大于0(不为空)
-z str str的长度为0(空串)
3. 整数操作符
var1 –eq var2 var1等于var2
var1 –ne var2 var1不等于var2
var1 –ge var2 var1大于等于var2
var1 –gt var2 var1大于var2
var1 –le var2 var1小于等于var2
var1 –lt var2 var1小于var2
4. 逻辑操作符
!expr 对expr求反
expr1 && expr2 对expr1与expr2求逻辑与,当expr1为假时不再执行expr2
expr1 || expr2 对expr1与expr2求逻辑或,当expr1为真时不再执行expr2
注:另一种逻辑操作符 逻辑与expr1 –a expr2 逻辑或expr1 –o expr2

五. Shell流控制
1. 条件语句:if
if 条件 IFS=:
then for dir in $PATH
语句 do
[elif 条件 if [ -O dir ]; then
语句] echo –e “\tYou own $dir”
[else else
语句] echo –e “\tYou don’t own $dir”
fi fi
2. 确定性循环:for done
for value in list for docfile in /etc/* /usr/etc/*
do do
statements using $value cp $docfile ${docfile%.doc}.txt
done done
注:for var;… 相当于for var in “$@”;…
3. 不确定性循环:while和until
while 条件 until 条件
do do
语句 语句
done done

count=1 count=1
while [ -n “$*” ] until [ -z “$*” ]
do do
echo "parameter $count" echo "parameter $count"
shift shift
count='expr $count + 1' count='expr $count + 1'
done done
条件为真执行循环体 条件为假执行循环体
注:整数变量的定义与算法
declare –i idx 定义整数变量 使用$(())无需定义
idx=1
while [ $idx!=150 ]
do
cp somefile somefile.$idx
idx=$idx+1 整数算法 idx=$(( $idx+1 ))
done
另一种算法 echo $(( 100/3 )) 将加减乘除表达式放入$(())中
4. 选择结构:case和select
case 表达式 in 表达式和模式依次比较,执行第一个匹配的模式
模式1) ;;使程序控制流跳到esac后执行,相当于break
语句;; 允许表达式和含有通配符的模式进行匹配
模式2)
语句;;
……
[*)
语句]
esac

select value [ in list ] 按list列表自动生成菜单
do 若没有list则默认为位置变量
statements using $value
done
如:IFS=: 设置域分隔符为:号
PS3=”choice>” 改变select默认提示符
clear
select dir in $PATH
do
if [ $dir ]; then
cnt=$(ls –Al $dir | wc -l)
echo “$cnt files in $dir”
else
echo “No such choice !”
fi
echo –e “\npress ENTER to continue, CTRL-C to quit”
read 使程序按回车继续,ctrl+c退出
clear
done
5. 命令shift
将存放在位置变量中的命令行参数依次向左传递
shift n 命令行参数向左传递n个串
六. Shell函数
定义: function fname fname ()
{ {
commands commands
} }
调用:fname [ parm1 parm2 parm3 ... ]
说明: 函数在使用前定义,两种定义功能相同
函数名和调用函数参数成为函数的位置变量
函数中的变量应该使用local声明为局部变量

七. 输入输出
限于篇幅,这里不讨论所有输入输出操作符和功能
1.I/O重定向
< :输入重定向
> :输出重定向(没有文件则创建,有则覆盖)
>> :输出重定向(没有则创建,有则追加到文件尾部)
<< :输入重定向(here文档)
格式: command << label
input…
label
说明: 使一个命令的输入为一段shell脚本(input…),直到标号(label)结束
如: cat < $HOME/.profile > out
echo “add to file end !” >> $HOME/.profile
ftp:USER=anonymous
PASS=YC@163.com
ftp –i –n << END -i:非交互模式 -n:关闭自动登录
open ftp.163.com
user $USER $PASS
cd /pub
close
END END标记输入结束
2.字符串I/O操作
字符串输出:echo
命令选项: -e:启动转义序列 -n:取消输出后换行
转义序列: \a:Alt/Ctrl+G(bell) \b:退格Backspace/Ctrl+H
\c:取消输出后换行 \f:Formfeed/Ctrl+J
\r:Return/Ctrl+M \v:Vertical tab
\n:八进制ASCII字符 \\:单个\字符 \t:Tab制表符
字符串输入:read
可以用于用户交互输入,也可以用来一次处理文本文件中的一行
命令选项: -a:将值读入数组,数组下标从0开始
-e:使用GNU的readline库进行读入,允许bash的编辑功能
-p:在执行读入前打印提示
如: IFS=:
read –p “start read from file . filename is : \c” filename
while read name pass uid gid gecos home shell < filename
do
echo –e “name : $name\npass : $pass\n”
done
说明:如果行的域数大于变量表的变量数,则后面的域全部追加给最后的变量

八. 命令行处理
命令行处理命令:getopts
有两个参数,第一个为字母和冒号组成的选项列表字符串,第二个为一个变量名
选项列表字符串以冒号开头的选项字母排列组成,如果一选项需要一个参数则该选项字母后跟一个冒号
getopts分解第一参数,依次将选项摘取出来赋给第二个参数变量
如果某选项有参数,则读取参数到内置变量OPTARG中
内置变量OPTIND保存着将被处理的命令行参数(位置参数)的数值
选项列表处理完毕getopts返回1,否则返回0
如: while getopts “:xy:z:” opt
do
case $opt in
x) xopt=’-x set’ ;;
y) yopt=”-y set and called with $OPTARG” ;;
z) zopt=”-z set and called with $OPTARG” ;;
\?) echo ‘USAGE: getopts.sh [-x] [-y arg] [-z arg] file…’
exit 1
esac
done
shift ($OPTING-1) 将处理过的命令行参数移去
echo ${xopt: -‘did not use –x‘}
echo ${yopt: -‘did not use –y‘}
echo ${zopt: -‘did not use –z‘}

echo “Remaining command-line arguments are :”
for f in “$@”
do
echo –e “\t$f\n”
done

九. 进程和作业控制
信号处理命令:trap
格式:trap command sig1 sig2 …
trap可以识别30多种信号,如中断(Ctrl+c)、挂起(Ctrl+z)等,可以使用kill -l查看信号清单
当脚本接受到信号sig1、sig2等,trap就执行命令command,command完成后脚本重新执行
信号可以通过名称或数字来标识
作业控制命令:bg、fg
bg:显示后台进程,即用Ctrl+z挂起或‘命令 &’执行的进程
fg:将后台进程转到前台执行
kill –9 %n:杀掉第n个后台进程
附录:
一. Bash支持的命令行参数
-a 将所有变量输出 
  -c "string"从string中读取命令 
  -e 使用非交互式模式 
  -f 禁止shell文件名产生 
  -h 定义 
  -i 交互式模式 
  -k 为命令的执行设置选项 
  -n 读取命令但不执行 
  -r 受限模式 
  -s 命令从标准输入读取 
  -t 执行一命令,然后退出shell 
  -u 在替换时,使用未设置的变量将会出错 
  -v 显示shell的输入行 
  -x 跟踪模式,显示执行的命令
许多模式可以组合起来用,使用set可以设置或取消shell的选项来改变shell环境。打开选项用"-",关闭选项用"+",若显示Shell中已经设置的选项,执行: $echo $-

二. .profile中shell的环境变量意思如下: 
CDPATH 执行cd命令时使用的搜索路径 
HOME 用户的home目录 
IFS 内部的域分割符,一般为空格符、制表符、或换行符 
MAIL 指定特定文件(信箱)的路径,有UNIX邮件系统使用 
PATH 寻找命令的搜索路径(同dos的config.sys的 path) 
PS1 主命令提示符,默认是"$" 
PS2 从命令提示符,默认是">" 
TERM 使用终端类型