2008-10-27 13 views
10

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

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

+0

У меня вопрос не возникает. Как кто-нибудь может сказать, что ваш скрипт сделал компакт-диск в новом каталоге? – 2008-10-27 17:37:36

+0

Текущие ответы подходят к этому из «правильного синтаксиса и не влияют на его родительскую оболочку, так что это нормально». Я вижу еще одну часть этого вопроса: «cd'ing в сценариях уродливого стиля кодирования, сродни чрезвычайно длинным строкам Python или слабо выбранным именам переменных - что-то, что можно сделать, но лучше всего избегать». – dfarrell07 2014-05-28 13:36:22

ответ

15

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

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

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

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

4

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

+0

Не на производных Unix, он не мог. – 2008-10-27 17:32:48

1

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

25

Как сказал Хьюго, вы не можете использовать cdd вашего родительского процесса, поэтому проблем нет.

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

Вы можете на это рукой ...

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... 
} 

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

2

Для 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 
    } 
3

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

ловушка "CD $ saved_dir" 0

вернется к saved_dir на подоболочек выходе (если вы .'ing файл).

микрофон

0

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

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

вместо

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

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