程序运行时总有一个相应的工作目录,后续要做的事都是从这个目录开始
借助标准模块之一的Cwd模块,我们可以看到当前的工作目录是哪个
use v5.10; use Cwd; say "The current working directory is ", getcwd();
打印出来的目录应该就是程序保存的位置
如果使用相对路径打开某个文件,perl会按当前目录定位这个相对路径
比如当前工作目录是/home/fred,运行以下代码来读取文件,perl会定位到/home/fred/relative/path.txt
# relative to the current working directory open my $fh, '<:utf8', 'relative/path.txt';
我们可以用标准模块之一的File::Spec实现相对路径和绝对路径之间的互相转换
2. 修改工作目录可以用chdir操作符修改当前工作目录
chdir '/etc' or die "cannot chdir to /etc: $!";
由于这是一个对操作系统的调用,所以出错时会设定$!的值。如果chdir返回假,则表示修改失败,应该立即检查$!中的错误原因
由perl程序启动的所有进程都会继承perl程序的工作目录。但对于调用perl程序的进程比如shell来说,它的工作目录是无法通过perl修改的。我们可以改动当前运行程序的工作目录,但无法改动父进程的工作目录。
如果调用chdir时不加参数,perl会猜想你要回到自己的用户主目录并试着将工作目录设成主目录。这是少数省略参数,却不使用$_变量的情况直以。chdir会依次查找环境变量$ENV{HOME}或$ENV{LOGDIR}并根据相应设定行事。如果没有给出预设路径,就什么都不做(如果是windows系统,还会返回失败)
某些运行环境并未设置此类环境变量,我们可以用File::HomeDir模块协助设定chdir检查的环境变量
可以用File::HomeDir模块去往特定用户的主目录,它支持大部分操作系统
3. 文件名通配$ echo *.pm barney.pm dino.pm fred.pm wilma.pm
这里的echo命令其实知道此刻用了文件名通配,因为shell会先把*.pm展开成一些符合条件的文件名,然后再交给echo处理,这对perl程序来说也是一样的
foreach $arg(@ARGV){
print "one arg is $argn";
}
运行程序时,如果只有一个带有通配符的参数,shell会先展开该通配模式,再把结果传递给程序,这样对程序来说就好像看到了多个参数
$ perl show-args *.pm one arg is barney.pm one arg is dino.pm one arg is fred.pm one arg is wilma.pm
需要注意的是,show-args完全不必了解如何进行文件名通配处理,放在@ARGV里的已经是展开好了的名称
有时候程序内部也可能需要用*.pm之类的模式,可以用glob操作符将它展开成相匹配的文件名
my @all_files = glob '*'; my @pm_files = glob '*.pm';
其中,@all_files会取得当前目录中的所有文件并按字母顺序排序,但不包括以点号开头的文件
任何能够在命令行上键入的模式都可以作为(唯一的)参数交给glob处理,如果要依次匹配多种模式,可以在参数中用空格隔开各个模式
my @all_files_including_dot = glob '.* *';
需要注意的是,在引号括住的字符串里,两个条目之间的空格是有意义的!它分隔了两个要进行文件名通配处理的条目
glob操作符的效果之所以和shell完全相同,是因为在perl5.6之前,glob只不过是在后台调用/bin/bash来展开文件名,因此文件名通配非常耗时,而且还可能在目录太大时(或别的情况下)崩溃
perl内置的glob并非唯一选择,可以用File::Glob模块提供各式兼容和扩展的文件名通配
4. 文件名通配的隐式语法过去写的程序使用尖括号语法来调用glob的功能,看起来就跟从文件句柄中读取差不多
my @all_files = <*>; # 和这样写一样一样的 my @all_files = glob "*";
perl会把尖括号内出现的变量替换成变量的值,类似于双引号内字符串的变量内插,这表示在进行文件名通配之前,perl会把变量展开位它的当前值
my $dir = '/etc'; my @dir_files = <$dir/* $dir/.*>;
这里的$dir会被展开
假如尖括号既表示从文件句柄读取又代表文件名通配操作,那perl是如何判断取舍的呢?
如果尖括号内是满足perl标识符条件的,就作为文件句柄来读取,否则,它代表的就是文件名通配操作
my @files =; # 文件名通配操作 my @lines = ; # 从文件句柄读取 my @lines = <$fred>; # 从文件句柄读取 my $name = 'FRED'; my @files = <$name/*>; # 通配模式
上述规则的唯一例外,就是当尖括号内仅是一个简单的标量变量(不是哈希或数组元素)时,那么它就是间接文件句柄读取(indirect filehandle read),其中变量的值就是待读取的文件句柄名称
my $name = 'FRED'; my @lines = <$name>; # 对句柄FRED进行间接文件句柄读取
perl会在编译阶段决定它时文件名通配还是从文件句柄读取,因此和变量内容无关
也可以用readline操作符执行间接文件句柄读取,让程序读起来更清楚些
my $name = 'FRED'; my @lines = readline FRED; # 从FRED读取 my @lines = readline $name; # 从FRED读取
不过因为间接文件句柄读取并不常见,并且通常也只用在简单的标量变量上,所以很少有用到readline操作符的机会



