bashまたはPerlスクリプト内のディレクトリを変更することは許容できると思いますか?それとも、これを絶対に避けるべきですか?
この問題のベストプラクティスは何ですか?
Hugoが言ったように、親プロセスのcwdに影響を与えることはできないので問題ありません。
質問がより適切なのは、サブルーチンやモジュールのようにプロセス全体を制御しない場合です。そのような場合、入力したのと同じディレクトリでサブルーチンを終了する必要があります。そうしないと、バグを引き起こす微妙な距離でのアクションが忍び寄ります。
手でこれを行うことができます...
use Cwd;
sub foo {
my $orig_cwd = cwd;
chdir "some/dir";
...do some work...
chdir $orig_cwd;
}
しかし、それには問題があります。サブルーチンが早期に戻るか終了する (そして例外がトラップされる) 場合、コードはsome/dir
. また、chdir
s が失敗する可能性があり、使用するたびに確認することを忘れないでください。ブレ。
幸いなことに、これを簡単にするモジュールがいくつかあります。File::pushd は 1 つですが、私はFile::chdirを好みます。
use File::chdir;
sub foo {
local $CWD = 'some/dir';
...do some work...
}
File::chdir は、ディレクトリの変更を への割り当てにし$CWD
ます。また、ローカライズ$CWD
して、スコープの最後にリセットされるようにすることもできます。また、chdir
が成功したかどうかを自動的にチェックし、それ以外の場合は例外をスローします。とても便利なので、スクリプトで使用することもあります。
現在の作業ディレクトリは実行中のシェルに対してローカルであるため、ユーザーがスクリプトを「ドット」(通常は新しいシェルプロセスを作成するのではなく、現在のシェルで実行)しない限り、ユーザーに影響を与えることはできません。
これを行うための非常に良い方法は、サブシェルを使用することです。これは、エイリアスでよく使用します。
alias build-product1='(cd $working-copy/delivery; mvn package;)'
パランセシスは、コマンドがサブシェルから実行されることを確認するため、シェルの作業ディレクトリに影響を与えません。また、last-working-directoryには影響しないため、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
}
私はこれを頻繁に行うことはありませんが、時にはかなりの頭痛の種を減らすことができます。ディレクトリを変更する場合は、必ず元のディレクトリに戻るようにしてください。そうしないと、コードパスを変更すると、アプリケーションが本来あるべきではない場所に残る可能性があります。
上記のSchwernとHugoのコメントを2番目にします。予期しない終了が発生した場合に元のディレクトリに戻ることについてのSchwernの注意に注意してください。彼はそれを処理するための適切なPerlコードを提供しました。シェル(Bash、Korn、Bourne)のトラップコマンドを指摘します。
トラップ"cd$ saved_dir" 0
サブシェルの終了時にsaved_dirに戻ります(ファイルを.'ingしている場合)。
マイク
Unix と Windows には組み込みのディレクトリ スタック、pushd と popdがあることも考慮してください。使い方はとても簡単です。
現在どのディレクトリにいるのかを推測せずに、完全に限定されたパスを試して使用することはまったく実行可能ですか? 例えば
use FileHandle;
use FindBin qw($Bin);
# ...
my $file = new FileHandle("< $Bin/somefile");
それよりも
use FileHandle;
# ...
my $file = new FileHandle("< somefile");
これは、奇妙なことが起こること (現在の作業ディレクトリを元の場所に戻す前にスクリプトが死んだり強制終了されたりすること) を心配する必要がないため、長期的にはおそらくより簡単であり、移植性が高い可能性があります。 .