更改脚本中的工作目录的最佳做法是什么?

时间:2008-10-27 17:09:55

标签: perl bash shell zsh

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

此问题的最佳做法是什么?

7 个答案:

答案 0 :(得分:26)

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

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

你可以手工制作......

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

    ...do some work...

    chdir $orig_cwd;
}

但这有问题。如果子例程提前返回或死亡(并且异常被捕获),则代码仍将在some/dir中。此外,chdir可能会失败,您必须记住检查每次使用。的Bleh。

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

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

    ...do some work...
}

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

答案 1 :(得分:16)

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

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

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

paranthesis将确保从子shell执行命令,因此不会影响我的shell的工作目录。它也不会影响last-working-directory,所以 cd - ; 按预期工作。

答案 2 :(得分:4)

我不经常这样做,但有时它可以节省相当多的头痛。请确保如果更改目录,则始终更改回您开始的目录。否则,更改代码路径可能会将应用程序留在不应该的位置。

答案 3 :(得分: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
  }

答案 4 :(得分:3)

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

陷阱“cd $ saved_dir”0

将在子shell退出时返回到saved_dir(如果你正在使用该文件)。

麦克

答案 5 :(得分:1)

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

答案 6 :(得分:0)

尝试使用完全量化的路径是否完全可行,而不是对您当前所在的目录做出任何假设? e.g。

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

而不是

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

从长远来看,这可能会更容易,因为您不必担心发生奇怪的事情(您的脚本在将当前工作目录恢复到原来的状态之前死亡或被杀死),并且相当可能更便携。