[Perl]如何复制档案及目录

use File::Copy;
copy('file1.txt','file2.txt') or die "can't copy: $!\n";

复制目录

sub copy_dir{
  my $source = $_[0];
  my $target = $_[1];
  use File::Copy;
  opendir(DIR,$source);
  while(my $filename = readdir(DIR)){
    if(-f "$source/$filename")){
      copy("$source/$filename","$target/$filename") or die "can't copy: $!\n";
    }
  }
  close(DIR);
}

参考网页

  • File::Copy - Copy files or filehandles
  • [转载][JavaScript]你所想像不到的 JavaScript

    转载自: 爱德华日志


    这不是一篇教你如何在网页中应用 JavaScript 的教材。这是一篇让你明了看似简单的 JavaScript,其实其核心语法功能强大。我将在这篇文章中说明 JavaScript 物件导向的特性,并说明如何透过这些特性,达到传统程式语言 (C++/Java) 所难以完成的功能。

    Everything is Object in JavaScript

    开宗明义:在 JavaScript 中任何东西都是物件:变量是物件、函式是物件,常数也是物件。证明方式:

    alert (typeof('abc'));
    alert (typeof(123));
    var ary = [123, "abc"];
    alert (typeof(ary));

    上面的 typeof 会显示物件资料型态。得到结果分别是 string, number, object。

    Create Objects in JavaScript

    既然任何东西都是物件,那建立物件的方法就多了。直接看个例子:

    var main = new Object;     // 建立新物件
    main.x = 123; // 设定物件成员变量(属性)之一
    main["y"] = "XYZ"; // 设定物件成员变量(属性)之二
    alert(main["x"]); // 取得物件属性并输出
    alert(main.y);

    可以看到在 JavaScript 中,main.x 与 main["x"] 这两种语法是通用的。其实在其他语言中,这两种表示法的语意并不相同。我稍后再作说明。

    List All Members in an Object

    这是 JavaScript 的必杀技,使用 JavaScript 的人务必要学会这个技巧。底下函式可以传回一个物件的所有成员的字串表达式,包括物件中的属性及方法。在物件导向程式设计中,这种技术叫 reflection。

    function listMember(main) {
      var s = "";
      for( key in main )  // 使用 in 运算子列举所有成员
      s += key + ": " + main[key] + "\n";
      return s;
    }

    范例码中的 key 会对应到物件中的属性名称,如 “x” 或 “y”,而 main[key] 则对应到属性值。

    说这项技巧是必杀技的原因是,你可以透过这项技巧,将物件封装的黑箱打开来,看看里面藏有什么东西。我常用这项技巧来看看 IE 与 Mozilla 的 Dom 物件模型有何不同。试试看下面呼叫范例,就可以知道这项技巧的强大了:

    var ary = [123, "abc"];
    alert (listMember(ary));
    alert (listMember(document.location));

    Construct Object with Initial Value

    要在建立物件的同时指定物件初始值,必须先透过 function 建立一个“原型物件”(或称为 constructor),再透过 new 运算子建立新物件。例如以下程式码会建立一个二维阵列的原型,再产生一个新的二维物件。

    function Array2DVar(x,y) {  // 定义二维阵列原型
      this.length = x;
      this.x = x;  // x 维度长度
      this.y = y;  // y 维度长度
      for(var i = 0; i < this.length; i++)  // 初始各元素值为 null
      this[i] = new Array(y);  // this 代表物件本身
    }
    
    var a2dv = new Array2DVar(10, 10);  // 建立新的 10*10 的二维阵列
    a2dv[1][3] = "ABC";  // 设定二维阵列元素值
    a2dv[2][6] = "XYZ";
    a2dv[9][9] = 1000;
    
    alert( a2dv[1][3]);  // 取得二维阵列元素值,并显示出来
    alert( a2dv[2][6]);
    alert( a2dv[9][9]);

    Initial Array Object

    在 JavaScript 中阵列也是物件 (其实近代多数语言中阵列也都是物件,只有像 C 或 Assembly 这类古老的语言才不把阵列看成物件),因此也可以用 constructor 的语法来建构。当然 JavaScript 还提供了 [] 语法,以更方便建构阵列,范例如下:

    a = new Array("abc", "xyz", 1000); // constructor 语法,或
    a = ["abc", "xyz", 1000]; // 阵列标准语法

    阵列的元素可以是简单的资料、其他物件,或是函数。举个例子来在阵列里面放函式:

    b = [ // 使用函式作为阵列元素
      function () { alert("这个好玩!") },
      function () { alert("再按一次离开!") },
      function () { alert("再来一次!") },
      function () { alert("最后一次!") }
    ];
    
    for (var i = 0; i < b.length ; i++)
    b[i]();

    最后一个 for 循环是个有趣的应用。由于 b 阵列中现在存放的所有元素都是函式,因此我们可以对 b 的每个元素进行呼叫。

    Object as Association Array

    关联阵列 (Assocation Array) 又称作 Map 或 Dictionary,是一种物件容器,其中可以放置许多的 key-value pair,以存取子物件。在JavaScript 中,物件本身就可以作为关连阵列。以关联阵列的方式初始化物件的范例如下:

    obj1 = {"a" : "Athens" , "b" : "Belgrade", "c" : "Cairo"};
    alert(obj1["a"]);  // 显示 Athens
    obj2 = {
      name: "Edward",
      showName: function() { alert(this.name); }  // 使用函式作为物件属性
    }
    obj2.showName();  // 显示 Edward
    obj2.age = 23;  // 属性可以动态加入

    其 中 obj1 储存了三个子元素,其键 (key) 为 “a”, “b” 与 “c”,而值 (value) 为 “Athens”, “Belgrade” 与 “Cairo”。obj2 中 showName 键所对应的值为 function,因此 obj2.showName() 即为函式呼叫。

    Object as Return Value

    虽然 Javascript 的函式只能传回一个变量,但您却可以将传回值设定为物件,达到传回 1个以上变量值的效果

    function a () {
      return [32, 17];
    }
    b = a();
    alert( b ); // 或
    alert(a());
    function pixel () {
      return {"x": 32, "y":17};
    }
    point = pixel ();
    alert (point.x + "\n" + point.y);  // 或
    alert (pixel().x + "\n" + pixel().y);

    Delegation Function Object

    函式也是物件,只是其中包含的是程式的逻辑。这项特性可拿来作为委任式的程式设计,亦即使用委任函式当作另一函式的参数:

    function doloop(begin, end, func) {  // 这个函式是个 iterator
      for (var i = begin; i < end; i++) {
        func(i);
      }
    }
    function func1(i) {  // 印出 ** n **
      document.writeln("** " + i + " **<br>");
    }
    doloop(1, 10, func1);  // 印出 10 行 ** n **
    doloop(20, 29,
      function(i) {  // 印出 10 行 ## n ##
        document.writeln("## " + i + " ##<br>");
      }
    );

    Object = Properties + Behaviors

    古有明训:程式 = 资料结构 + 算法。而物件是建构程式的基本单位,自然的具有相同的性质。物件除了有属性 (property),也可具有操作 (behavior),也就是函式。

    假如我们要使用一维阵列来模拟二维阵列,那么就无法使用 ary[x][y] 这种表示法来设定或取得阵列成员。不过我可以定义一个 set 方法来设定成员变量,而以 get 方法来取得成员变量值。原型函式定义如下:

    function Array2D(x,y){  // 以一维阵列模拟二维阵列的原型物件
      this.length = x * y;  // 阵列总长
      this.x = x;  // x 维度长度
      this.y = y;  // y 维度长度
      for(var i = 0; i < this.length; i++)  // 初始各元素值为 null
        this[i] = null;
      this.get = function(x,y){  // 成员函式:取得阵列第 [x,y]个元素值
        return this[x*this.x + y];
      }
      this.set = function(x,y,value){  // 成员函式:设定阵列第 [x,y] 个元素值
        this[x*this.x + y] = value;
      }
    }

    我们接着来使用它:

    var a2d = new Array2D(10, 10);  // 建立新的“二维”阵列
    
    a2d.set(1, 3, "ABC");  // 设定“二维”阵列元素值
    a2d.set(2, 6, "XYZ");
    a2d.set(9, 9, 1000);
    
    alert( a2d.get(1,3) );  // 取得“二维”阵列元素值,并显示出来
    alert( a2d.get(2,6) );
    alert( a2d.get(9,9) );

    Member Function Outside of Constructor

    我们也可以将物件成员函式写于原型物件之外。以下的 Array2D 物件与上一个范例中的 Array2D 物件有相同的作用,只不过这次是写在原型物件之外。

    function Array2D(x,y){  // 以一维阵列模拟二维阵列的原型物件
      this.length = x * y;  // 阵列总长
      this.x = x;  // x 维度长度
      this.y = y;  // y 维度长度
      for(var i = 0; i < this.length; i++)  // 初始各元素值为 null
        this[i] = null;
      this.get = Array2DGet;  // 用这种方式把成员函式挂进来
      this.set = Array2DSet;
    }
    
    function Array2DGet(x,y){  // 成员函式:取得阵列第 [x,y] 个元素值
      return this[x*this.x + y];
    }
    
    function Array2DSet(x,y,value){  // 成员函式:设定阵列第 [x,y] 个元素值
      this[x*this.x + y] = value;
    }

    Dynamic Object Function

    这里说明如何为一个已定义物件,动态的加上其他操作的方法。

    如果一物件已定义完成,而您也使用它来建立了新的物件,这时候您想为原型物件增加新的操作 (而不修改原型物件的原始码),让所有该物件的复本都能使用该操作,该如何达成呢?方法是使用物件的 prototype 属性。以下这个例子,为 Array 这类 Object 在执行期加入一个 max 方法,以取得阵列元素之最大值 (修改自微软 jscript.chm之范例):

    function array_max(){  // 定义求取 Array 最大值之函式
      var i, max = this[0];
      for (i = 1; i < this.length; i++){
      if (max < this[i])
        max = this[i];
      }
      return max;
    }
    Array.prototype.max = array_max;  // 在 Array 原型中加入 max 函式

    上面的程式码,首先建立一个 array_max 方法,以求取阵列之最大元素。接着将这个方法设定给 Array 原型物件。

    var x = new Array(1, 2, 3, 4, 5, 6);  // 透过 Array 建构子建立一阵列,想求取 x 中某一元素之最大值
    var y = x.max( );  // 取得 x 之最大元素

    Dynamic Mix in

    假如物件 dynamic 有 method1, method2 两个函式;而另一物件 main 有 methodA 及 methodB 两个函式。现在我想把 dynamic 的所有特性 (feature) 汇入到 main 中,我们可以在 main 中加上一个 imports 函式:

    function main(){  // main 之建构子
      // ...
      this.imports =
        function (object) {
          if( typeof object == "object")
            for( value in object )
              this[value] = object[value];
        }
      // ...
    }
    obj = new main();
    main.imports(new dynamic());  // 汇入 dynamic 物件之所有功能

    这个 imports 函式可以动态的为 main 加上另一物件的所有操作。这种 Mix in 的功能可是 C++/Java 的 static type 语言所望尘莫及的。

    IP 位址区段计算程式 *

    档案下载

    有时候 MIS 需要计算区段 IP 的启始位置和终点 IP,使用这个程式,只需要填入目标 IP,就会帮您算出:

    • IP 数
    • 开始的 IP(Network IP)
    • 结束的 IP(Brocase IP)
    • 网络遮罩(Subnet Mask)

    而且不用安装就可以使用了。

    .htaccess 简易的网页帐号认证

    .htaccess 让你不用写程式,就可以用最简单的方式做出“网页登入”的功能,限制哪些用户能进到网页的某一层目录。

    建立用户验证资料

    建立用户验证档

    建立用户验证档,并新增一组帐号及密码:

    htpasswd -c /path/to/.htusers UserName1

    这里所产生的 .htusers 是一个文字档,里面会有用户名称及编码过的密码。第一次建立档案时,必须加 -c 参数。同时,请找一个安全的地方放置 .htusers 这个档案,所谓的“安全”是指至少不要在公开网页可以被下载到的路径,例如放在 public_html 的上一层。

    继续增加第二组帐号及密码到验证档时,就不用加 -c 参数:

    htpasswd /path/to/.htusers UserName2

    建立群组资料档

    如果用户比较多,你可能会想要用群组的方式来做管理。群组资料档的目的是要将多个用户设为一个群组,请新增或编辑 /path/to/.htgroups,依需求增加类似如下的设定:

    Group1:UserName1 UserName2

    代表 Group1 包含 UserName1UserName2 这两个用户。

    验证登入

    在欲执行用户验证的网页目录下,建立一个 .htaccess 档案,验证的方式可针对用户或群组,差别在于 require 这个参数。

    针对用户:

    AuthName "Restricted Area" # 名称必须用英文
    AuthType Basic
    AuthUserFile /path/to/.htusers
    require user UserName1 # 仅针对特定用户,以空白分隔多个用户

    上述的最后一行是只有 UserName1 允许进入,你也可以改成:

    require valid-user # 针对全部用户

    表示针对 .htusers 里的所有用户。

    针对群组:

    AuthName "Restricted Area" # 名称必须用英文
    AuthType Basic
    AuthUserFile /path/to/.htusers
    AuthGroupFile /path/to/.htgroups
    require group Group1 # 仅针对特定群组的用户,以空白分隔多个群组

    表示针对 .htgroups 里,归属于 Group1 下的用户。

    针对特定档案:

    若你只想针对特定档案做保护,那可以与 <Files>~</Files> 一起使用:

    <Files FileName>
         require valid-user
    </Files>

    <Files>~</Files> 一次只能填写一个档案,但支援正规表示式。以下是使用正规表示式限制图档存取的范例:

    <Files ~ "\.(gif|jpe?g|png)$">
         require valid-user
    </Files>

    或是:

    <FilesMatch "\.(gif|jpe?g|png)$">
         require valid-user
    </FilesMatch>

    设定好之后,当用户要存取该目录 (或档案),就会跳出叫你登入的对话框:


    另外,你也可以在网址中直接输入你的帐号、密码,格式:

     http://UserName:Password@www.example.com/directory/

    问题排除

    如果在设定 htaccess 认证方式之后,在进入网页时,仍然没有跳出验证的对话框,则请编辑 /etc/httpd/conf/httpd.conf,搜寻相关的“AllowOverride”设定,改成:

    AllowOverride All

    安全性问题

    虽然用户储存在 Server 端的密码有经过加密,但因为是采用 Basic 方式验证,当要存取网页时,用户输入的帐号与密码仅是以 Base64 编码,包裹在 Headers 里进行传输,有机会被窃听之后解码、盗用! 网站必须导入 SSL 才能完全在传输的过程中加密。

    参考网页

    Who Is Connected 1.6.1 - 让骇客现形

    档案下载

    你是否觉得电脑的执行速度突然变慢?是否想知道有没有人在存取你电脑上的资料?是否觉得网络速度越变越慢?是否担心你的电脑被植入了木马程式?Who Is Connected 这套软件就可以帮你解决这些疑问。虽然这套软件全部是英文界面,但还是画面简单,不须太高深的网络知识,很适合一般家用电脑使用者。它的好处是,当你发现有可疑连线入侵时,可以马上阻断连线,并列入为禁止连线的黑名单。你也可在断线时,先发出 Message 询问对方到底有何用意。
    Read more

    [转载]Unicode 脱逸序列转换

    转载自: IT Inside


    这里提供一段程式码,可以透过 JavaScript 将文字转换为 Unicode 脱逸序列。这段程式码,不论是对网页开发人员,还是对 java resource bundle 的翻译人员,都有很大的方便性。使用时只要将底下的程式码复制起来,以 html 副档名储存,就可以用 browser 执行了。

    <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=big5">
    <script language=javascript>
    <!--
    function StringToUniCode(source) {
      sret = "";
      // Unicode 跳脱序列之格式为 \u00ff
      for(var i=0; i < source.length; i++) {
       var num = new Number( source.charCodeAt(i));
       sret += "\\u" + num.toString(16);
      }
      return sret;
    }
    function convert(){
      document.forms.content.result.value = StringToUniCode(document.forms.content.source.value);
    }
    //-->
    </script>
    将文字转成 Unicode 跳脱序列
    <form name=content>
    来源:<input type=TEXT name=source size=40 value="常用连络人"><br />
    结果:<input type=TEXT name=result size=40><br />
    <input type=button value=转换 onclick="convert()">
    </form>

    UltraFXP 1.07 - 高效能的 FTP 程式

    档案下载

    这是一个高效能的 FTP 程式,也是我认为最强的 FTP 程式,因为产品版权的争议,UltraFXP 的 1.07 版,改为 Freeware 发行。不过,现在已经被买走了,改名叫 FTPRush,恢复成 ShareWare 继续发行。

    Read more

    在 Linux 上建立虚拟主机最快速的方法 *

    本篇的目的,是说明如何使用最简单的方式在你的网页服务器 (Apache) 上新增一个虚拟主机 (Virtual Host),让你只要建一个目录,或新增一个本机用户,就可以建立虚拟主机,并且可自动分割 Log 档 (以下之设定牵涉到 Apache 及 DNS 的观念,最好也有自行架设 DNS 服务)。
    Read more

    Redhat Linux 9.0 中文手册 *

    档案下载

    内含 Redhat Linux 9.0 的安装手册、使用手册及用户自订手册,HTML 格式。

    你也可以到这里读取:

    相关网页

    HTTP 回应的代码含义

    当我们在浏览网页的时候,经常会看到诸如 500 错误之类的讯息,这些错误代码所代表的含义作为网站的开发人员,应该必须了解的。

    HTTP 的回应代码是三位数字,其中第一个数字定义了代码的类别:

    范围 类别 含义
    100~199 讯息 请求被接收,正在处理
    200~299 成功 动作被成功接收、理解和接受
    300~399 重新导向 必须采取其他动作才能完成请求
    400~499 用户错误 请求包含不良语法或无法完成
    500~599 服务器错误 服务器无法处理的请求

    其中较常见的 HTTP 回应代码有:

    • 200: 请求成功
    • 400: 语法错误
    • 401: 未经授权
    • 403: 禁止访问
    • 404: 请求的网页不存在
    • 500: 服务器错误

    Read more

    return top