对于这个问题,最佳实践是什么?
正如Hugo所说,您无法影响父进程的当前工作目录,因此没有问题。
如果您不控制整个过程,例如在子例程或模块中,则更适用于该问题。在这些情况下,您希望退出子例程时与进入时处于相同的目录,否则会出现导致错误的微妙的跨越操作。
您可以手动完成此操作...
use Cwd;
sub foo {
my $orig_cwd = cwd;
chdir "some/dir";
...do some work...
chdir $orig_cwd;
}
但这种方法存在问题。如果子程序提前返回或异常中止(并且异常被捕获),则您的代码仍将在 some/dir
目录下运行。此外,chdir
可能会失败,而您必须记住检查每次使用。呃。
幸运的是,有几个模块可以使这更加容易。File::pushd 是其中之一,但我更喜欢 File::chdir。
use File::chdir;
sub foo {
local $CWD = 'some/dir';
...do some work...
}
File::chdir会将目录更改为分配给$CWD
。您可以将$CWD
本地化,以便在作用域结束时重置,而不管是否成功。它还会自动检查chdir
是否成功,否则会引发异常。有时在脚本中使用它非常方便。
当前工作目录是相对于执行的shell本地化的,所以除非用户"点"(在当前shell中运行它,而不是通常情况下创建一个新的shell进程运行它),否则您无法影响用户运行脚本。
一个非常好的方法是使用子shell,在别名中我经常这样做。
alias build-product1='(cd $working-copy/delivery; mvn package;)'
使用括号可以确保命令在子shell中执行,因此不会影响我的shell的工作目录。同时,它也不会影响最后一个工作目录,所以cd -;按预期工作。
对于Perl,您可以使用来自CPAN的File::pushd模块,使本地更改工作目录变得非常优雅。引用摘要:
use File::pushd;
chdir $ENV{HOME};
# change directory again for a limited scope
{
my $dir = pushd( '/tmp' );
# working directory changed to /tmp
}
# working directory has reverted to $ENV{HOME}
# tempd() is equivalent to pushd( File::Temp::tempdir )
{
my $dir = tempd();
}
# object stringifies naturally as an absolute path
{
my $dir = pushd( '/tmp' );
my $filename = File::Spec->catfile( $dir, "somefile.txt" );
# gives /tmp/somefile.txt
}
我并不经常这样做,但有时这样做可以节省很多麻烦。只要确保如果您更改目录,始终要返回到您开始的目录。否则,更改代码路径可能会使应用程序停留在不该去的地方。
trap“cd $saved_dir”0
将在子shell退出时返回到saved_dir(如果您正在使用该文件)。
mike
尝试使用完全限定路径而不对你当前所在的目录进行任何假设,这是否有可能?例如:
use FileHandle;
use FindBin qw($Bin);
# ...
my $file = new FileHandle("< $Bin/somefile");
而不是
use FileHandle;
# ...
my $file = new FileHandle("< somefile");
从长远来看,这可能会更容易,因为您不必担心发生奇怪的事情(脚本在将当前工作目录放回原处之前死亡或被杀死),而且可能更具可移植性。