Quelle est la meilleure pratique pour changer les répertoires de travail dans les scripts?

StackOverflow https://stackoverflow.com/questions/240661

  •  04-07-2019
  •  | 
  •  

Question

Pensez-vous que la modification de répertoires dans les scripts bash ou Perl est acceptable? Ou faut-il éviter cela à tout prix?

Quelle est la meilleure pratique pour ce problème?

Était-ce utile?

La solution

Le répertoire de travail en cours est local par rapport au shell en cours d'exécution. Vous ne pouvez donc affecter l'utilisateur que s'il est "en pointillé". (en l'exécutant dans le shell actuel, par opposition à l'exécution normale d'un nouveau processus shell), votre script.

Un très bon moyen de faire cela consiste à utiliser des sous-shell, ce que je fais souvent dans les alias.

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

La parenthèse s'assurera que la commande est exécutée à partir d'un sous-shell et n'affectera donc pas le répertoire de travail de mon shell. De plus, cela n'affectera pas le dernier répertoire de travail, donc cd -; fonctionnera comme prévu.

Autres conseils

Comme Hugo l'a dit, vous ne pouvez pas affecter le traitement de votre processus parent, il n'y a donc aucun problème.

La question qui s’applique plus facilement est si vous ne contrôlez pas l’ensemble du processus, comme dans un sous-programme ou un module. Dans ces cas, vous souhaitez quitter le sous-programme dans le même répertoire que celui que vous avez entré. Sinon, une action subtile à distance se produit qui provoque des bogues.

Vous pouvez le faire à la main ...

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

    ...do some work...

    chdir $orig_cwd;
}

mais cela a des problèmes. Si le sous-programme retourne plus tôt ou meurt (et que l'exception est capturée), votre code sera toujours dans some / dir . De plus, les chdir peuvent échouer et vous devez vous rappeler de vérifier chaque utilisation. Bleh.

Heureusement, il existe quelques modules pour vous faciliter la tâche. Fichier :: pushd en est un, mais je préfère Fichier :: chdir .

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

    ...do some work...
}

File :: chdir permet de modifier les répertoires en attribuant à $ CWD . Et vous pouvez localiser $ CWD afin qu'il se réinitialise à la fin de votre portée, quoi qu'il arrive. Il vérifie également automatiquement si chdir réussit et génère une exception dans le cas contraire. Parfois, il l’utilise dans les scripts parce que c’est tellement pratique.

Je ne le fais pas souvent, mais parfois, cela peut éviter beaucoup de maux de tête. Assurez-vous simplement que si vous changez de répertoire, vous revenez toujours au répertoire dans lequel vous avez commencé. Sinon, la modification des chemins de code pourrait laisser l’application quelque part qu’elle ne devrait pas être.

Pour Perl, vous disposez du module File :: pushd de CPAN. le changement local du répertoire de travail est assez élégant Citant le synopsis:

  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
  }

J'appuie les commentaires de Schwern et Hugo ci-dessus. Notez la mise en garde de Schwern concernant le retour au répertoire d'origine en cas de sortie inattendue. Il a fourni le code Perl approprié pour gérer cela. Je signalerai la commande de capture du shell (Bash, Korn, Bourne).

trap " cd $ saved_dir " 0

retournera à saved_dir à la sortie du sous-shell (si vous utilisez le fichier.).

mike

Considérez également qu'Unix et Windows ont une pile de répertoires intégrée: pushd and popd . C’est extrêmement facile à utiliser.

Est-il possible d'essayer d'utiliser des chemins entièrement quantifiés et de ne pas présumer du répertoire dans lequel vous vous trouvez actuellement? par exemple

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

plutôt que

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

Cela sera probablement plus facile à long terme, car vous n’aurez plus à vous soucier de choses étranges (votre script est en train de mourir ou d’être tué avant de pouvoir remettre le répertoire de travail actuel à son emplacement actuel), et c'est tout à fait normal. peut-être plus portable.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top