Какая наилучшая практика для изменения рабочих каталогов внутри скриптов?

Считаете ли вы, что изменение каталогов внутри сценариев bash или Perl приемлемо? Или следует избегать делать это любой ценой?

Какова наилучшая практика для этой проблемы?

Ответ 1

Текущий рабочий каталог является локальным для исполняющей оболочки, поэтому вы не можете влиять на пользователя, если он не "точечный" (запуск в текущей оболочке, а не запуск его, как правило, создание нового процесса оболочки). script.

Очень хороший способ сделать это - использовать подоболочки, которые я часто делаю в псевдонимах.

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

Паратезис будет гарантировать, что команда выполняется из под-оболочки и, таким образом, не повлияет на рабочий каталог моей оболочки. Также это не повлияет на последний рабочий каталог, поэтому cd -; работает как ожидалось.

Ответ 2

Как сказал Хьюго, вы не можете повлиять на ваш родительский процесс cwd, чтобы не было проблем.

Если вопрос более применим, это если вы не контролируете весь процесс, например, в подпрограмме или модуле. В тех случаях вы хотите выйти из подпрограммы в том же каталоге, в каком вы ввели, в противном случае тонкие крики действий на расстоянии, в которых возникают ошибки.

Вы можете это сделать вручную...

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

    ...do some work...

    chdir $orig_cwd;
}

но это имеет проблемы. Если подпрограмма вернется раньше или умрет (и исключение попадает в ловушку), ваш код по-прежнему будет находиться в some/dir. Кроме того, chdir может выйти из строя, и вы должны помнить о каждом использовании. BLEH.

К счастью, есть несколько модулей, чтобы сделать это проще. Файл:: pushd - один, но я предпочитаю File::chdir.

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

    ...do some work...
}

Файл:: chdir позволяет сменить каталоги на присвоение $CWD. И вы можете локализовать $CWD, чтобы он был reset в конце вашей области, независимо от того, что. Он также автоматически проверяет, удался ли chdir и выбрал исключение иначе. Иногда он используется в скриптах, потому что это так удобно.

Ответ 3

Я не часто это делаю, но иногда это может сэкономить немало головной боли. Просто убедитесь, что если вы меняете каталоги, вы всегда меняете обратно в каталог, с которого вы начали. В противном случае изменение путей кода могло бы оставить приложение где-то не должно быть.

Ответ 4

Я остановлюсь на комментариях Шерна и Хьюго выше. Обратите внимание, что Шверн предупреждает о возврате в исходный каталог в случае неожиданного выхода. Он предоставил соответствующий код Perl для обработки этого. Я укажу на команду оболочки (Bash, Korn, Bourne).

trap "cd $saved_dir" 0

вернется к save_dir на выходе из подоболочки (если вы находитесь в файле).

микрофон

Ответ 5

Для Perl у вас есть модуль File:: pushd от CPAN, который делает локальное изменение рабочего каталога довольно элегантным. Цитирование резюме:

  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
  }

Ответ 6

Считайте также, что Unix и Windows имеют встроенный стек каталогов: pushd и popd. Его чрезвычайно прост в использовании.

Ответ 7

Можно ли вообще попытаться использовать полностью квантифицированные пути и не делать каких-либо предположений о том, в какой директории вы сейчас находитесь? например.

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

а не

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

В конечном итоге это будет легче, так как вам не нужно беспокоиться о странных вещах (ваш script умирает или убивается, прежде чем он сможет вернуть текущий рабочий каталог туда, где он был), и вполне возможно более портативен.