12

您认为更改 bash 或 Perl 脚本中的目录是否可以接受?还是应该不惜一切代价避免这样做?

这个问题的最佳实践是什么?

4

7 回答 7

26

就像雨果说的,你不能影响你的父进程的 cwd 所以没有问题。

如果您不控制整个过程,例如在子例程或模块中,则问题更适用。在这些情况下,您希望退出与您输入相同的目录中的子例程,否则微妙的远距离动作会导致错误。

你可以手动完成这个...

use Cwd;
sub foo {
    my $orig_cwd = cwd;
    chdir "some/dir";

    ...do some work...

    chdir $orig_cwd;
}

但这有问题。如果子例程提前返回或终止(并且异常被捕获),您的代码仍将位于some/dir. 此外,chdirs 可能会失败,您必须记住检查每次使用。呜呜。

幸运的是,有几个模块可以让这更容易。File::pushd 是其中之一,但我更喜欢File::chdir

use File::chdir;
sub foo {
    local $CWD = 'some/dir';

    ...do some work...
}

File::chdir 将目录更改为分配给$CWD. 而且您可以进行本地化$CWD,因此无论如何它都会在您的范围结束时重置。它还会自动检查是否chdir成功,否则抛出异常。有时它会在脚本中使用它,因为它非常方便。

于 2008-10-27T21:41:36.437 回答
16

当前工作目录是执行 shell 的本地目录,因此您不能影响用户,除非他“打点”(在当前 shell 中运行它,而不是正常运行它创建一个新的 shell 进程)您的脚本。

这样做的一个很好的方法是使用子shell,我经常在别名中这样做。

alias build-product1='(cd $working-copy/delivery; mvn package;)'

括号将确保命令是从子 shell 执行的,因此不会影响我的 shell 的工作目录。它也不会影响最后一个工作目录,所以cd -; 按预期工作。

于 2008-10-27T17:19:16.123 回答
4

我不经常这样做,但有时它可以避免相当多的头痛。只要确保如果您更改目录,您总是会更改回您开始的目录。否则,更改代码路径可能会将应用程序留在不应该出现的地方。

于 2008-10-27T17:12:39.757 回答
4

对于 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
  }
于 2008-10-27T22:02:54.553 回答
3

我将支持上面 Schwern 和 Hugo 的评论。请注意 Schwern 关于在意外退出时返回原始目录的警告。他提供了适当的 Perl 代码来处理这个问题。我将指出 shell(Bash、Korn、Bourne)陷阱命令。

陷阱“cd $saved_dir”0

将在 subshel​​l 退出时返回到 saved_dir(如果你正在 .'ing 文件)。

麦克风

于 2008-10-27T22:11:29.420 回答
1

还要考虑 Unix 和 Windows 有一个内置的目录堆栈:pushd 和 popd。它非常易于使用。

于 2008-10-27T21:35:52.363 回答
0

尝试使用完全量化的路径并且不对您当前所在的目录做出任何假设是否可行?例如

use FileHandle;
use FindBin qw($Bin);
# ...
my $file = new FileHandle("< $Bin/somefile");

而不是

use FileHandle;
# ...
my $file = new FileHandle("< somefile");

从长远来看,这可能会更容易,因为您不必担心发生奇怪的事情(您的脚本在将当前工作目录放回原来的位置之前死亡或被杀死),并且很可能更便携.

于 2008-10-28T04:06:35.367 回答