php设计模式之适配器模式

没有评论

2011 年 09 月 29 日 at 下午 11:04分类:PHP

适配器模式使用场景:
1、你想使用一个已经存在的类,而它的接口不符合你的需求
2、你想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类协同工作
3、你想使用一个已经存在的子类,但是不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以适配它的父类接口(仅限于对象适配器)

<?php
/**
  * 适配器模式
  *
  * 将一个类的接口转换成客户希望的另外一个接口,使用原本不兼容的而不能在一起工作的那些类可以在一起工作
  */
 
 // 这个是原有的类型
 class OldCache
 {
     public function __construct()
     {
         echo "OldCache construct<br/>";
     }
 
     public function store($key,$value)
     {
         echo "OldCache store<br/>";
     }
 
     public function remove($key)
     {
         echo "OldCache remove<br/>";
     }
 
     public function fetch($key)
     {
         echo "OldCache fetch<br/>";
     }
 }
 
 interface Cacheable
 {
     public function set($key,$value);
     public function get($key);
     public function del($key);
 }
 
 class OldCacheAdapter implements Cacheable
 {
     private $_cache = null;
     public function __construct()
     {
         $this->_cache = new OldCache();
     }
 
     public function set($key,$value)
     {
         return $this->_cache->store($key,$value);
     }
 
     public function get($key)
     {
         return $this->_cache->fetch($key);
     }
 
     public function del($key)
     {
         return $this->_cache->remove($key);
     }
 }
 
 $objCache = new OldCacheAdapter();
 $objCache->set("test",1);
 $objCache->get("test");
 $objCache->del("test",1);

【适配器模式中主要角色】
目标(Target)角色:定义客户端使用的与特定领域相关的接口,这也就是我们所期待得到的
源(Adaptee)角色:需要进行适配的接口
适配器(Adapter)角色:对Adaptee的接口与Target接口进行适配;适配器是本模式的核心,适配器把源接口转换成目标接口,此角色为具体类
【类适配器模式与对象适配器】
类适配器:Adapter与Adaptee是继承关系
1、用一个具体的Adapter类和Target进行匹配。结果是当我们想要一个匹配一个类以及所有它的子类时,类Adapter将不能胜任工作
2、使得Adapter可以重定义Adaptee的部分行为,因为Adapter是Adaptee的一个子集
3、仅仅引入一个对象,并不需要额外的指针以间接取得adaptee
对象适配器:Adapter与Adaptee是委托关系
1、允许一个Adapter与多个Adaptee同时工作。Adapter也可以一次给所有的Adaptee添加功能
2、使用重定义Adaptee的行为比较困难

详细请看:点击查看

php设计模式之观察者模式

没有评论

2011 年 09 月 28 日 at 下午 11:03分类:PHP

观察者模式是一种非常简单的事件系统,包含了两个或更多的互相交互的类。这一模式允许某个类观察另一个类的状态。当被观察者的状态发生改变时,就会通知所有观察者进行相应的变化。
在观察者模式中,被观察者称为subject,观察者称为observer,为了表达这些内容,SPL(Standard PHP Libaray)提供了SplSubject(被观察者)和SplObserver(观察者)两个接口。在编写观察者模式时,只要实现这两个接口即可。
接口如下:

    //被观察者接口
   interface SplSubject{
      public function attach(SplObserver $observer);//注册观察者(注册的观察者:当我(被观察者)的某个状态改变时,需要通知的对象)
      public function detach(SplObserver $observer);//释放观察者
      public function notify();//通知所有注册的观察者的方法
   }
     //观察者接口
     interface SplObserver{
      public function update(SplSubject $subject);//观察者进行更新状态
     }

这一模式的概念是SplSubject类维护了一个特定状态,当这个状态发生变化时,它就会调用notify()方法。调用notify()方法时,所有之前使用attach()方法注册的SplObserver实例的update方法都会被调用。
以下是实现代码:

  <?php
//被观察者实现类
class DemoSubject implements SplSubject {

  private $observers, $value;

  public function __construct() {
    $this->observers = array();
  }
//注册观察者
  public function attach(SplObserver $observer) {
    $this->observers[] = $observer;
  }
 //释放观察者
  public function detach(SplObserver $observer) {
    if($idx = array_search($observer,$this->observers,true)) {
      unset($this->observers[$idx]);
    }
  }
 //通知所有观察者
  public function notify() {
    foreach($this->observers as $observer) {
      $observer->update($this);
    }
  }
//设置状态,当状态发生任何变化时,都会调用notify方法通知所有的观察者
  public function setState($value) {
    $this->value = $value;
    $this->notify();
  }
//
  public function getValue() {
    return $this->value;
  }

}
//观察者简单类
class DemoObserver implements SplObserver {

  //接收被观察者发送的通知
  public function update(SplSubject $subject) {
    echo 'The new value is '. $subject->getValue();
  }

}

$subject = new DemoSubject();//初始化被观察者
$observer = new DemoObserver();//初始化一个观察者
$subject->attach($observer);//添加一个观察者
$subject->setState(5);//被观察者修改状态。
?>;

输出结果为:
The new value is 5
观察者模式的优点在于,挂接到被观察者上的观察者可多可少,并且不需要提前知道哪个观察者会响应被观察者发出的响应事件。

PHP设计模式之组合设计模式

没有评论

2011 年 09 月 27 日 at 下午 11:57分类:PHP

<?php 
/**
 * 组合模式
 * @desc 组合模式(Composite):将对象组合成树形结构以表示'部分-整体'的层次结构。组合模式使得用户对单个对象和
 *    组合对象的使用具有一致性。
 *          使用场景: 当发现需求中是体现部分与整体层次的结构时,以及希望用户可以忽略组合对象与单个对象的不同,统一的使用组合结构
 *    中的所有对象时。
 *  @author perisky
 */

//公司类  抽象类及接口
abstract class Company {
    protected $name;
    
    public function __construct($name) {
        $this->name = $name;
    }
    
    public abstract function add($company);            //增加
    public abstract function remove($company);        //移除
    public abstract function display($depth);        //显示
}

//具体公司类
class ConcreteCompany extends Company {
    private $_companyList = array();
    
    public function add($company) {
        $unique = substr(md5(serialize($company)), 0, 3);
        $this->_companyList[$unique] = $company;
    }
    
    public function remove($company) {
        $unique = substr(md5(serialize($company)), 0, 3);
        unset($this->_companyList[$unique]);
    }
    
    public function display($depth) {
        $rst = str_repeat('-', $depth);
        echo $rst.$this->name."\r\n</br>";
        foreach ($this->_companyList as $v) {                        
            $v->display($depth+2);            
        }
    }
}

//人力资源部
class HRDepartment extends Company {
    public function add($company) {    
        return '';
    }
    
    public function remove($company) { 
        return '';
    }
    
    public function display($depth) {    
        $rst  =  str_repeat('-', $depth);
        $rst .=  $this->name."\r\n</br>";
        echo $rst;
    }
}

//财务部
class FinanceDepartment extends Company {
    public function add($company) {
        return '';
    }
    
    public function remove($company) { 
        return '';
    }
    
    public function display($depth) {    
        $rst  =  str_repeat('-', $depth);
        $rst .=  $this->name."\r\n</br>";
        echo $rst;
    }
}


$root = new ConcreteCompany('成都总公司');
$root->add(new HRDepartment('总公司人力资源部'));
$root->add(new FinanceDepartment('总公司财务部'));

$comp1 = new ConcreteCompany('广元分公司');
$comp1->add(new HRDepartment('广元分公司人力资源部'));
$comp1->add(new FinanceDepartment('广元分公司财务部'));
$root->add($comp1);

$comp2 = new ConcreteCompany('南充分公司');
$comp2->add(new HRDepartment('南充分公司人力资源部'));
$comp2->add(new FinanceDepartment('南充分公司财务部'));
$root->add($comp2);

$comp3 = new ConcreteCompany('苍溪办事处');
$comp3->add(new HRDepartment('苍溪办事处人力资源部'));
$comp3->add(new FinanceDepartment('苍溪办事处财务部'));
$comp1->add($comp3);

$root->display(1);

页面显示效果:
-成都总公司
—总公司人力资源部
—总公司财务部
—广元分公司
—–广元分公司人力资源部
—–广元分公司财务部
—–苍溪办事处
——-苍溪办事处人力资源部
——-苍溪办事处财务部
—南充分公司
—–南充分公司人力资源部
—–南充分公司财务部

接口和抽象类的区别

没有评论

2011 年 09 月 25 日 at 下午 9:35分类:PHP

本质区别:抽象类中可以有非抽象的方法而接口中只能够有抽象的方法!

我想,对于各位使用面向对象编程语言的程序员来说,“接口”这个名词一定不陌生,但是不知各位有没有这样的疑惑:接口有什么用途?它和抽象类有什么区别?能不能用抽象类代替接口呢?而且,作为程序员,一定经常听到“面向接口编程”这个短语,那么它是什么意思?有什么思想内涵?和面向对象编程是什么关系?本文将一一解答这些疑问。

1.面向接口编程和面向对象编程是什么关系

首先,面向接口编程和面向对象编程并不是平级的,它并不是比面向对象编程更先进的一种独立的编程思想,而是附属于面向对象思想体系,属于其一部分。或者说,它是面向对象编程体系中的思想精髓之一。

2.接口的本质

接口,在表面上是由几个没有主体代码的方法定义组成的集合体,有唯一的名称,可以被类或其他接口所实现(或者也可以说继承)。它在形式上可能是如下的样子:

interface InterfaceName
{
    void Method1();
    void Method2(int para1);
    void Method3(string para2,string para3);
}

那么,接口的本质是什么呢?或者说接口存在的意义是什么。我认为可以从以下两个视角考虑:

1)接口是一组规则的集合,它规定了实现本接口的类或接口必须拥有的一组规则。体现了自然界“如果你是……则必须能……”的理念。

例如,在自然界中,人都能吃饭,即“如果你是人,则必须能吃饭”。那么模拟到计算机程序中,就应该有一个IPerson(习惯上,接口名由“I”开头)接口,并有一个方法叫Eat(),然后我们规定,每一个表示“人”的类,必须实现IPerson接口,这就模拟了自然界“如果你是人,则必须能吃饭”这条规则。

从这里,我想各位也能看到些许面向对象思想的东西。面向对象思想的核心之一,就是模拟真实世界,把真实世界中的事物抽象成类,整个程序靠各个类的实例互相通信、互相协作完成系统功能,这非常符合真实世界的运行状况,也是面向对象思想的精髓。

2)接口是在一定粒度视图上同类事物的抽象表示。注意这里我强调了在一定粒度视图上,因为“同类事物”这个概念是相对的,它因为粒度视图不同而不同。

例如,在我的眼里,我是一个人,和一头猪有本质区别,我可以接受我和我同学是同类这个说法,但绝不能接受我和一头猪是同类。但是,如果在一个动物学家眼里,我和猪应该是同类,因为我们都是动物,他可以认为“人”和“猪”都实现了IAnimal这个接口,而他在研究动物行为时,不会把我和猪分开对待,而会从“动物”这个较大的粒度上研究,但他会认为我和一棵树有本质区别。

现在换了一个遗传学家,情况又不同了,因为生物都能遗传,所以在他眼里,我不仅和猪没区别,和一只蚊子、一个细菌、一颗树、一个蘑菇乃至一个SARS病毒都没什么区别,因为他会认为我们都实现了IDescendable这个接口(注:descend vi. 遗传),即我们都是可遗传的东西,他不会分别研究我们,而会将所有生物作为同类进行研究,在他眼里没有人和病毒之分,只有可遗传的物质和不可遗传的物质。但至少,我和一块石头还是有区别的。

可不幸的事情发生了,某日,地球上出现了一位伟大的人,他叫列宁,他在熟读马克思、恩格斯的辩证唯物主义思想巨著后,颇有心得,于是他下了一个著名的定义:所谓物质,就是能被意识所反映的客观实在。至此,我和一块石头、一丝空气、一条成语和传输手机信号的电磁场已经没什么区别了,因为在列宁的眼里,我们都是可以被意识所反映的客观实在。如果列宁是一名程序员,他会这么说:所谓物质,就是所有同时实现了“IReflectabe”和“IEsse”两个接口的类所生成的实例。(注:reflect v. 反映 esse n. 客观实在)

也许你会觉得我上面的例子像在瞎掰,但是,这正是接口得以存在的意义。面向对象思想和核心之一叫做多态性,什么叫多态性?说白了就是在某个粒度视图层面上对同类事物不加区别的对待而统一处理。而之所以敢这样做,就是因为有接口的存在。像那个遗传学家,他明白所有生物都实现了IDescendable接口,那只要是生物,一定有Descend()这个方法,于是他就可以统一研究,而不至于分别研究每一种生物而最终累死。

可能这里还不能给你一个关于接口本质和作用的直观印象。那么在后文的例子和对几个设计模式的解析中,你将会更直观体验到接口的内涵。

3.面向接口编程综述

通过上文,我想大家对接口和接口的思想内涵有了一个了解,那么什么是面向接口编程呢?我个人的定义是:在系统分析和架构中,分清层次和依赖关系,每个层次不是直接向其上层提供服务(即不是直接实例化在上层中),而是通过定义一组接口,仅向上层暴露其接口功能,上层对于下层仅仅是接口依赖,而不依赖具体类。

这样做的好处是显而易见的,首先对系统灵活性大有好处。当下层需要改变时,只要接口及接口功能不变,则上层不用做任何修改。甚至可以在不改动上层代码时将下层整个替换掉,就像我们将一个WD的60G硬盘换成一个希捷的160G的硬盘,计算机其他地方不用做任何改动,而是把原硬盘拔下来、新硬盘插上就行了,因为计算机其他部分不依赖具体硬盘,而只依赖一个IDE接口,只要硬盘实现了这个接口,就可以替换上去。从这里看,程序中的接口和现实中的接口极为相似,所以我一直认为,接口(interface)这个词用的真是神似!

使用接口的另一个好处就是不同部件或层次的开发人员可以并行开工,就像造硬盘的不用等造CPU的,也不用等造显示器的,只要接口一致,设计合理,完全可以并行进行开发,从而提高效率。

本篇文章先到这里。最后我想再啰嗦一句:面向对象的精髓是模拟现实,这也可以说是我这篇文章的灵魂。所以,多从现实中思考面向对象的东西,对提高系统分析设计能力大有脾益。

下篇文章,我将用一个实例来展示接口编程的基本方法。

而第三篇,我将解析经典设计模式中的一些面向接口编程思想,并解析一下.NET分层架构中的面向接口思想。

对本文的补充:

仔细看了各位的回复,非常高兴能和大家一起讨论技术问题。感谢给出肯定的朋友,也要感谢提出意见和质疑的朋友,这促使我更深入思考一些东西,希望能借此进步。在这里我想补充一些东西,以讨论一些回复中比较集中的问题。

1.关于“面向接口编程”中的“接口”与具体面向对象语言中“接口”两个词

看到有朋友提出“面向接口编程”中的“接口”二字应该比单纯编程语言中的interface范围更大。我经过思考,觉得很有道理。这里我写的确实不太合理。我想,面向对象语言中的“接口”是指具体的一种代码结构,例如C#中用interface关键字定义的接口。而“面向接口编程”中的“接口”可以说是一种从软件架构的角度、从一个更抽象的层面上指那种用于隐藏具体底层类和实现多态性的结构部件。从这个意义上说,如果定义一个抽象类,并且目的是为了实现多态,那么我认为把这个抽象类也称为“接口”是合理的。但是用抽象类实现多态合理不合理?在下面第二条讨论。

概括来说,我觉得两个“接口”的概念既相互区别又相互联系。“面向接口编程”中的接口是一种思想层面的用于实现多态性、提高软件灵活性和可维护性的架构部件,而具体语言中的“接口”是将这种思想中的部件具体实施到代码里的手段。

2.关于抽象类与接口

看到回复中这是讨论的比较激烈的一个问题。很抱歉我考虑不周没有在文章中讨论这个问题。我个人对这个问题的理解如下:

如果单从具体代码来看,对这两个概念很容易模糊,甚至觉得接口就是多余的,因为单从具体功能来看,除多重继承外(C#,Java中),抽象类似乎完全能取代接口。但是,难道接口的存在是为了实现多重继承?当然不是。我认为,抽象类和接口的区别在于使用动机。使用抽象类是为了代码的复用,而使用接口的动机是为了实现多态性。所以,如果你在为某个地方该使用接口还是抽象类而犹豫不决时,那么可以想想你的动机是什么。

看到有朋友对IPerson这个接口的质疑,我个人的理解是,IPerson这个接口该不该定义,关键看具体应用中是怎么个情况。如果我们的项目中有Women和Man,都继承Person,而且Women和Man绝大多数方法都相同,只有一个方法DoSomethingInWC()不同(例子比较粗俗,各位见谅),那么当然定义一个AbstractPerson抽象类比较合理,因为它可以把其他所有方法都包含进去,子类只定义DoSomethingInWC(),大大减少了重复代码量。

但是,如果我们程序中的Women和Man两个类基本没有共同代码,而且有一个PersonHandle类需要实例化他们,并且不希望知道他们是男是女,而只需把他们当作人看待,并实现多态,那么定义成接口就有必要了。

总而言之,接口与抽象类的区别主要在于使用的动机,而不在于其本身。而一个东西该定义成抽象类还是接口,要根据具体环境的上下文决定。

再者,我认为接口和抽象类的另一个区别在于,抽象类和它的子类之间应该是一般和特殊的关系,而接口仅仅是它的子类应该实现的一组规则。(当然,有时也可能存在一般与特殊的关系,但我们使用接口的目的不在这里)如,交通工具定义成抽象类,汽车、飞机、轮船定义成子类,是可以接受的,因为汽车、飞机、轮船都是一种特殊的交通工具。再譬如Icomparable接口,它只是说,实现这个接口的类必须要可以进行比较,这是一条规则。如果Car这个类实现了Icomparable,只是说,我们的Car中有一个方法可以对两个Car的实例进行比较,可能是比哪辆车更贵,也可能比哪辆车更大,这都无所谓,但我们不能说“汽车是一种特殊的可以比较”,这在文法上都不通。

SWFUPLOAD上传插件使用方法

没有评论

2011 年 09 月 24 日 at 下午 5:14分类:JavaScript | PHP

详细使用方法:
点击查看详细

php获取远程图片的两种简单方式

一条评论

2011 年 09 月 15 日 at 下午 4:55分类:PHP

方式1:curl

<?php

$url = "http://thinkphp.cn/Public/Uploads/thinkphp_ad01.gif";

$filename = 'curl.gif';

getImg($url, $filename);

/*
  *@通过curl方式获取制定的图片到本地
  *@ 完整的图片地址
  *@ 要存储的文件名
 */
function getImg($url = "", $filename = "") {
	if(is_dir(basename($filename))) {
		echo "The Dir was not exits"; 
		Return false;
	}
	//去除URL连接上面可能的引号
	$url = preg_replace( '/(?:^[\'"]+|[\'"\/]+$)/', '', $url );

	$hander = curl_init();
	$fp = fopen($filename,'wb');
	
	curl_setopt($hander,CURLOPT_URL,$url);
	curl_setopt($hander,CURLOPT_FILE,$fp);
	curl_setopt($hander,CURLOPT_HEADER,0);
	curl_setopt($hander,CURLOPT_FOLLOWLOCATION,1);
	//curl_setopt($hander,CURLOPT_RETURNTRANSFER,false);//以数据流的方式返回数据,当为false是直接显示出来
	curl_setopt($hander,CURLOPT_TIMEOUT,60);

	/*$options = array(
		CURLOPT_URL=> 'http://thinkphp.cn/Public/Uploads/thinkphp_ad01.gif',
		CURLOPT_FILE => $fp,
		CURLOPT_HEADER => 0,
		CURLOPT_FOLLOWLOCATION => 1,
		CURLOPT_TIMEOUT => 60
	); 
	curl_setopt_array($hander, $options);
	*/

	curl_exec($hander);
	curl_close($hander);
	fclose($fp);
	Return true;
}

?>

///////////////////////////////////////////////////////////////////////
方式2:sockets

$a = "http://thinkphp.cn/Public/Uploads/thinkphp_ad01.gif";

$local = 'socket1.gif';

$aa = getImg($a,$local);

/*
  *@ 完整的图片地址
  *@ 要存储的文件名
 */
function getImg( $url = "", $filename = "" ) {
	if(is_dir(basename($filename))) {
		echo "The Dir was not exits"; 
		Return false;
	}
	//去除URL连接上面可能的引号
	$url = preg_replace( '/(?:^[\'"]+|[\'"\/]+$)/', '', $url );
	if (!extension_loaded('sockets')) return false;
	//获取url各相关信息
	preg_match( '/http:\/\/([^\/\:]+(\:\d{1,5})?)(.*)/i', $url, $matches );
	if (!$matches) return false;
	$sock = socket_create( AF_INET, SOCK_STREAM, SOL_TCP );
	if ( !@socket_connect( $sock, $matches[1], $matches[2] ? substr($matches[2], 1 ) : 80 ) ) {
		return false;
	}
	//图片的相对地址
	$msg = 'GET ' . $matches[3] . " HTTP/1.1\r\n";
	//主机名称
	$msg .= 'Host: ' . $matches[1] . "\r\n";
	$msg .= 'Connection: Close' . "\r\n\r\n";
	socket_write( $sock, $msg );
	$bin = '';
	while ( $tmp = socket_read( $sock, 10 ) ) {
		$bin .= $tmp;
		$tmp = '';
	}
	$bin = explode("\r\n\r\n", $bin);
	$img = $bin[1];
	$h = fopen( $filename, 'wb' );
	$res = fwrite( $h, $img ) === false ? false : true;
	@socket_close( $sock );
	Return $res;
}

防止伪造跨站请求的小招式

没有评论

2011 年 09 月 07 日 at 下午 11:26分类:PHP

伪造跨站请求介绍
  伪造跨站请求比较难以防范,而且危害巨大,攻击者可以通过这种方式恶作剧,发spam信息,删除数据等等。这种攻击常见的表现形式有:
  伪造链接,引诱用户点击,或是让用户在不知情的情况下访问
  伪造表单,引诱用户提交。表单可以是隐藏的,用图片或链接的形式伪装。
  比较常见而且也很廉价的防范手段是在所有可能涉及用户写操作的表单中加入一个随机且变换频繁的字符串,然后在处理表单的时候对这个字符串进行检查。这个随机字符串如果和当前用户身份相关联的话,那么攻击者伪造请求会比较麻烦。
  yahoo对付伪造跨站请求的办法是在表单里加入一个叫.crumb的随机串;而facebook也有类似的解决办法,它的表单里常常会有post_form_id和fb_dtsg。
随机串代码实现
  咱们按照这个思路,山寨一个crumb的实现,代码如下:

<?php 
class Crumb {                                                                                                   
 
    CONST SALT = "your-secret-salt";                                                          
 
    static $ttl = 7200;                                                                                            
 
    static public function challenge($data) { 
        return hash_hmac('md5', $data, self::SALT); 
    }                                                                                                              
 
    static public function issueCrumb($uid, $action = -1) { 
        $i = ceil(time() / self::$ttl); 
        return substr(self::challenge($i . $action . $uid), -12, 10); 
    }                                                                                                              
 
    static public function verifyCrumb($uid, $crumb, $action = -1) { 
        $i = ceil(time() / self::$ttl);                                                                            
 
        if(substr(self::challenge($i . $action . $uid), -12, 10) == $crumb || 
            substr(self::challenge(($i - 1) . $action . $uid), -12, 10) == $crumb) 
            return true;                                                                                           
 
        return false; 
    }                                                                                                              
 
} 

代码中的$uid表示用户唯一标识,而$ttl表示这个随机串的有效时间。
  应用示例
  构造表单
  在表单中插入一个隐藏的随机串crumb

<form method="post" action="demo.php"> 
<input type="hidden" name="crumb" value="<?php echo Crumb::issueCrumb($uid)?>"> 
<input type="text" name="content"> 
<input type="submit"> 
</form> 

处理表单 demo.php
  对crumb进行检查

<?php 
if(Crumb::verifyCrumb($uid, $_POST['crumb'])) { 
    //按照正常流程处理表单 
} else { 
    //crumb校验失败,错误提示流程 
}

Shell 尴尬一: syntax error:unexpected end of file

没有评论

2011 年 09 月 02 日 at 上午 9:38分类:Linux

在windows下写好了Shell 但是在linux下用
>> sh -n [filesName] 检查语法总是出一个错误 syntax error:unexpected end of file
原因如下:
dos文件传输到unix系统时,会在每行的结尾多一个^M,在vi的时候,当你用如下命令:
>>vi dos.txt
>>:set fileformat=unix
>>:w
就会看到这些存在于每行结尾的^M符号,这个就是产生syntax error:unexpected end of file的原因

解决方案:
在vi下把这些^M都删除后, 搞定!

PS:
当你确定你的shell脚本没有语法错误的时候,而总是报错,那么你可以看看是不是上面说的编码问题。。

Linux下的bg和fg命令说明

一条评论

2011 年 09 月 02 日 at 上午 9:33分类:Linux

我们都知道,在 Windows 上面,我们要么让一个程序作为服务在后台一直运行,要么停止这个服务。而不能让程序在前台后台之间切换。而 Linux 提供了 fg 和 bg 命令,让我们轻松调度正在运行的任务。

假设你发现前台运行的一个程序需要很长的时间,但是需要干其他的事情,你就可以用 Ctrl-Z ,挂起这个程序,然后可以看到系统提示(方括号中的是作业号):
[1]+ Stopped /root/bin/rsync.sh
然后我们可以把程序调度到后台执行:(bg 后面的数字为作业号)
#bg 1
[1]+ /root/bin/rsync.sh &
用 jobs 命令查看正在运行的任务:
#jobs
[1]+ Running /root/bin/rsync.sh &
如果想把它调回到前台运行,可以用
#fg 1
/root/bin/rsync.sh
这样,你在控制台上就只能等待这个任务完成了。

fg、bg、jobs、&、ctrl + z都是跟系统任务有关的,虽然现在基本上不怎么需要用到这些命令,但学会了也是很实用的
一。& 最经常被用到
这个用在一个命令的最后,可以把这个命令放到后台执行
二。ctrl + z
可以将一个正在前台执行的命令放到后台,并且暂停
三。jobs
查看当前有多少在后台运行的命令
四。fg
将后台中的命令调至前台继续运行
如果后台中有多个命令,可以用 fg %jobnumber将选中的命令调出,%jobnumber是通过jobs命令查到的后台正在执行的命令的序号(不是pid)
五。bg
将一个在后台暂停的命令,变成继续执行
如果后台中有多个命令,可以用bg %jobnumber将选中的命令调出,%jobnumber是通过jobs命令查到的后台正在执行的命令的序号(不是pid)