Perl文件名通配和文件查找

在shell中使用*來對文件名進行通配擴展,在Perl中也一樣支持文件名通配。並且perl中的glob通配方式和shell的通配方式徹底一致,實際上perl的glob函數就是直接調用csh來通配的(若是不存在csh,則使用其它shell),也所以通配是一個效率較低的操做。sql

glob通配函數

元字符    意義
--------------------------------
[]       字符類,匹配中括號中的任一字符。注:
*        匹配任意個字符
?        匹配任意單個字符,注意,不匹配0個
~        匹配家目錄

注意:shell

  • []支持[0-9] [a-z] [A-Z] [A-z]相似的範圍通配,其中[A-z]等價於[A-Za-z]
  • 不支持[^]取反
  • 特別須要注意的是[1-34]通配的是[1234],而不是1到34,由於中括號只能匹配單個字符

例如:app

use 5.010;

say glob "*";      # 匹配當前目錄下全部非"."開頭的隱藏文件
say glob ".* *";   # 匹配當前目錄下全部文件,包括"."開頭的隱藏文件
say glob "23.p[ly]";  # 匹配23.pl或23.py文件
say glob "[0-9][0-9].pl"   # 匹配兩個數值開頭的pl文件
say glob "/root/23.p?";   # 匹配家目錄下後綴以p開頭,後面還有一個字符的文件
say glob "~/*.sh";  # 匹配家目錄下的全部sh文件

在glob函數中,空格具備特殊含義,若是想要匹配包含空格的文件名,必須將其使用引號(單/雙引號皆可)包圍。函數

例如,要匹配"hello world.log"文件:工具

glob "'hello w*.log'";
glob '"hello w*.log"';
glob qq('hello w*.log');
glob qq("hello w*.log");
glob q('hello w*.log');
glob q("hello w*.log");

File::Glob模塊提供更豐富的通配規則,能夠去查看下手冊。不過說實話,用到的幾乎應該很少。ui

尖括號<>通配寫法

在glob出現以前,人們都使用尖括號表達式來通配。它和glob的實現是徹底一致的,僅僅只是從尖括號改成了glob函數。unix

例如,匹配/root下的sh文件,下面兩種寫法徹底等價:code

say </root/*.sh>;
say glob "/root/*.sh";

還可使用變量替換:ssl

$dir="/etc";
my @file_list = glob "$dir/*.sh $dir/*.py";
my @file_list = <$dir/*.sh $dir/*.py>;

一樣,匹配包含空格的文件,可能須要使用引號包圍:openssl

say <"hello w*.log">;

在這裏須要搞清楚尖括號內的到底會被解析成文件句柄仍是解析成通配符。perl的解析規則是:假如尖括號內的內容知足標識符規則(文件句柄的名稱要知足此規則),則會解析爲文件句柄,不然解析成通配符。

如下是幾種狀況的區分示例:

my @files = <FOO/*>;     # 文件名通配
my @lines = <FOO>;       # 讀取文件句柄
my @lines = <$fred>;     # 讀取文件句柄
my $name = 'FOO';
my @files = <$name>;     # 讀取文件句柄
my @files = <$name/*>;   # 文件名通配

從第三行和第5行能夠看出,當使用變量且只有變量名替換的時候,會優先解析爲文件句柄。

文件查找:關於find2perl腳本

在unix下有一個find工具,用來查找文件很是方便。perl提供了一個find2perl的工具(該工具是在安裝perl時自帶的),它能夠將find查找文件時的表達式轉換成perl對應的查找語句。

find2perl的選項和用法和find的用法99%都同樣,只有幾項額外的是find2perl自身提供的,但這樣的選項很是少。

注意,find2perl不是文件查找工具,而是將咱們寫的find命令表達式轉換爲等價的perl文件查找語句。

例如,搜索/etc目錄下全部".cnf"結尾的文件,find命令的表達式以下:

find /etc -type f -name "*.cnf"

執行find2perl:

[root@xuexi perlapp]# find2perl /etc/ -type f -name "*.cnf"
#! /usr/bin/perl -w
    eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
        if 0; #$running_under_some_shell

use strict;
use File::Find ();

# Set the variable $File::Find::dont_use_nlink if you're using AFS,
# since AFS cheats.

# for the convenience of &wanted calls, including -eval statements:
use vars qw/*name *dir *prune/;
*name   = *File::Find::name;
*dir    = *File::Find::dir;
*prune  = *File::Find::prune;

sub wanted;



# Traverse desired filesystems
File::Find::find({wanted => \&wanted}, '/etc/');
exit;


sub wanted {
    my ($dev,$ino,$mode,$nlink,$uid,$gid);

    (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) &&
    -f _ &&
    /^.*\.cnf\z/s
    && print("$name\n");
}

能夠看出,上面生成了一個wanted子程序,之後要查找"/etc/*.cnf"文件時,只需調用wanted子程序便可。例如:

[root@xuexi perlapp]# find2perl /etc/ -type f -name "*.cnf" >24.plx
[root@xuexi perlapp]# chmod +x 24.plx 
[root@xuexi perlapp]# perl 24.plx 
/etc/my.cnf
/etc/proxysql.cnf
/etc/pki/tls/openssl.cnf
相關文章
相關標籤/搜索