bash 更改脚本内工作目录的最佳做法是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/240661/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What's the best practice for changing working directories inside scripts?
提问by Tom Feiner
Do you think changing directories inside bash or Perl scripts is acceptable? Or should one avoid doing this at all costs?
您认为在 bash 或 Perl 脚本中更改目录是否可以接受?还是应该不惜一切代价避免这样做?
What is the best practice for this issue?
这个问题的最佳实践是什么?
回答by Schwern
Like Hugo said, you can't effect your parent process's cwd so there's no problem.
就像 Hugo 说的,你不能影响你的父进程的 cwd,所以没有问题。
Where the question is more applicable is if you don't control the whole process, like in a subroutine or module. In those cases you want to exit the subroutine in the same directory as you entered, otherwise subtle action-at-a-distance creeps in which causes bugs.
问题更适用的地方是,如果您不控制整个过程,例如在子程序或模块中。在这些情况下,您希望退出您输入的同一目录中的子程序,否则会导致错误的微妙远距离动作蔓延。
You can to this by hand...
您可以手动完成此操作...
use Cwd;
sub foo {
my $orig_cwd = cwd;
chdir "some/dir";
...do some work...
chdir $orig_cwd;
}
but that has problems. If the subroutine returns early or dies (and the exception is trapped) your code will still be in some/dir. Also, the chdirs might fail and you have to remember to check each use. Bleh.
但这有问题。如果子例程提前返回或死亡(并且异常被捕获),您的代码仍将位于some/dir. 此外,chdirs 可能会失败,您必须记住检查每次使用。布莱。
Fortunately, there's a couple modules to make this easier. File::pushd is one, but I prefer File::chdir.
幸运的是,有几个模块可以使这更容易。File::pushd 是其中之一,但我更喜欢File::chdir。
use File::chdir;
sub foo {
local $CWD = 'some/dir';
...do some work...
}
File::chdir makes changing directories into assigning to $CWD. And you can localize $CWDso it will reset at the end of your scope, no matter what. It also automatically checks if the chdirsucceeds and throws an exception otherwise. Sometimes it use it in scripts because it's just so convenient.
File::chdir 将目录更改为分配给$CWD. 而且您可以进行本地化,$CWD因此无论如何它都会在您的范围结束时重置。它还自动检查是否chdir成功,否则抛出异常。有时它在脚本中使用它,因为它非常方便。
回答by Hugo
The current working directory is local to the executing shell, so you can't affect the user unless he is "dotting" (running it in the current shell, as opposed to running it normally creating a new shell process) your script.
当前工作目录对于正在执行的 shell 来说是本地的,因此您不能影响用户,除非他“打点”(在当前 shell 中运行它,而不是正常运行它以创建新的 shell 进程)您的脚本。
A very good way of doing this is to use subshells, which i often do in aliases.
一个很好的方法是使用子shell,我经常用别名来做。
alias build-product1='(cd $working-copy/delivery; mvn package;)'
The paranthesis will make sure that the command is executed from a sub-shell, and thus will not affect the working directory of my shell. Also it will not affect the last-working-directory, so cd -;works as expected.
括号将确保命令是从子 shell 执行的,因此不会影响我的 shell 的工作目录。它也不会影响最后一个工作目录,所以cd -; 按预期工作。
回答by Ovid
I don't do this often, but sometimes it can save quite a bit of headache. Just be sure that if you change directories, you always change back to the directory you started from. Otherwise, changing code paths could leave the application somewhere it should not be.
我不经常这样做,但有时它可以节省相当多的头痛。只要确保如果你改变目录,你总是回到你开始的目录。否则,更改代码路径可能会将应用程序留在不应该存在的地方。
回答by tsee
For Perl, you have the File::pushdmodule from CPAN which makes locally changing the working directory quite elegant. Quoting the synopsis:
对于 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
}
回答by mpez0
I'll second Schwern's and Hugo's comments above. Note Schwern's caution about returning to the original directory in the event of an unexpected exit. He provided appropriate Perl code to handle that. I'll point out the shell (Bash, Korn, Bourne) trap command.
我将在上面附上 Schwern 和 Hugo 的评论。注意 Schwern 关于在意外退出时返回原始目录的警告。他提供了适当的 Perl 代码来处理这个问题。我将指出 shell(Bash、Korn、Bourne)陷阱命令。
trap "cd $saved_dir" 0
陷阱 "cd $saved_dir" 0
will return to saved_dir on subshell exit (if you're .'ing the file).
将在子shell 退出时返回saved_dir(如果你正在.'ing 文件)。
mike
麦克风
回答by Jon Shea
Consider also that Unix and Windows have a built in directory stack: pushd and popd. It's extremely easy to use.
还要考虑 Unix 和 Windows 有一个内置的目录堆栈:pushd 和 popd。它非常容易使用。
回答by Sam Kington
Is it at all feasible to try and use fully-quantified paths, and not make any assumptions on which directory you're currently in? e.g.
尝试使用完全量化的路径并且不对您当前所在的目录做出任何假设是否完全可行?例如
use FileHandle;
use FindBin qw($Bin);
# ...
my $file = new FileHandle("< $Bin/somefile");
rather than
而不是
use FileHandle;
# ...
my $file = new FileHandle("< somefile");
This will probably be easier in the long run, as you don't have to worry about weird things happening (your script dying or being killed before it could put the current working directory back to where it was), and is quite possibly more portable.
从长远来看,这可能会更容易,因为您不必担心会发生奇怪的事情(您的脚本在将当前工作目录放回原来的位置之前就死掉或被杀死),并且很可能更便携.

