Como faço para obter o caminho completo para um script Perl que está em execução?

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

  •  01-07-2019
  •  | 
  •  

Pergunta

Eu tenho Perl script e necessidade de determinar o caminho completo e nome do script durante a execução. Descobri que, dependendo de como você chamar o $0 roteiro varia e às vezes contém o fullpath+filename e às vezes apenas filename. Porque o diretório de trabalho pode variar assim eu não consigo pensar em uma maneira de forma confiável obter o fullpath+filename do script.

Alguém tem uma solução?

Foi útil?

Solução

Existem algumas maneiras:

  • $0 é o script atualmente em execução, como previsto pelo POSIX, em relação ao trabalho atual diretório se o script é igual ou inferior a CWD
  • Além disso, cwd(), getcwd() e abs_path() são fornecidos pela Cwd módulo e dizer-lhe onde o roteiro está sendo executado a partir
  • O módulo FindBin fornece os $Bin & $RealBin variáveis ??que normalmente são o caminho para o script de execução; Este módulo também fornece $Script & $RealScript que são o nome do script
  • __FILE__ é o arquivo real que o intérprete Perl lida com durante a compilação, incluindo seu caminho completo.

Eu vi os três primeiros ( $0 , a Cwd módulo e o FindBin módulo) falhar sob mod_perl espetacularmente, produzindo saída inútil, como '.' ou uma string vazia. Em tais ambientes, eu uso __FILE__ e obter o caminho de que o uso do File::Basename módulo:

use File::Basename;
my $dirname = dirname(__FILE__);

Outras dicas

$ 0 é normalmente o nome do seu programa, assim como sobre isso?

use Cwd 'abs_path';
print abs_path($0);

Parece-me que isso deve funcionar como abs_path sabe se você estiver usando um caminho relativo ou absoluto.

Atualizar Para quem lê este anos mais tarde, você deve ler a resposta de Drew abaixo. É muito melhor que o meu.

Use File::Spec;
File::Spec->rel2abs( __FILE__ );

http://perldoc.perl.org/File/Spec/Unix.html

Eu acho que o módulo que você está procurando FindBin:

#!/usr/bin/perl
use FindBin;

$0 = "stealth";
print "The actual path to this is: $FindBin::Bin/$FindBin::Script\n";

Você pode usar FindBin , Cwd , File :: baseName , ou uma combinação deles. Eles estão todos na distribuição base do Perl IIRC.

Eu costumava Cwd no passado:

Cwd:

use Cwd qw(abs_path);
my $path = abs_path($0);
print "$path\n";

Obtendo o caminho absoluto para $0 ou __FILE__ é o que você quer. O único problema é se alguém fez um chdir() eo $0 era relativa -. Então você precisa para obter o caminho absoluto em um BEGIN{} para evitar quaisquer surpresas

tentativas FindBin para sair um pouco melhor e rastejar em torno da $PATH por algo que corresponde ao basename($0), mas há momentos em que faz coisas muito-muito-surpreendentes (especificamente: quando o arquivo é "direito na frente de você" no cwd.)

File::Fu tem File::Fu->program_name e File::Fu->program_dir para isso.

Alguns curta background:

Infelizmente o Unix API não fornece um programa rodando com o caminho completo para o executável. Na verdade, o programa de execução de seu pode fornecer tudo o que quer no campo que diz normalmente o seu programa o que é. Há, como todas as respostas apontam, várias heurísticas para encontrar candidatos prováveis. Mas nada menos do que pesquisar todo o sistema de arquivos será sempre funciona, e mesmo que falhará se o executável é movido ou removido.

Mas você não quer que o executável Perl, que é o que está realmente em execução, mas o script é executado. E Perl precisa saber onde está o script para encontrá-lo. Ele armazena isso no __FILE__, enquanto $0 é a partir da API do Unix. Isso ainda pode ser um caminho relativo, assim que tomar a sugestão de Mark e canonizar com File::Spec->rel2abs( __FILE__ );

Você tentou:

$ENV{'SCRIPT_NAME'}

ou

use FindBin '$Bin';
print "The script is located in $Bin.\n";

Ela realmente depende de como está sendo chamado e se é CGI ou a ser executado a partir de um shell normal, etc.

A fim de obter o caminho para o diretório que contém o meu script eu usei uma combinação de respostas já dadas.

#!/usr/bin/perl
use strict;
use warnings;
use File::Spec;
use File::Basename;

my $dir = dirname(File::Spec->rel2abs(__FILE__));

perlfaq8 responde a uma pergunta muito semelhante com o uso da função rel2abs() em $0. Essa função pode ser encontrada em File :: Spec.

Não há necessidade de usar módulos externos, com apenas uma linha você pode ter o nome do arquivo e caminho relativo. Se você estiver usando módulos e necessidade de aplicar um caminho relativo para o diretório de script, o caminho relativo é suficiente.

$0 =~ m/(.+)[\/\\](.+)$/;
print "full path: $1, file name: $2\n";
#!/usr/bin/perl -w
use strict;


my $path = $0;
$path =~ s/\.\///g;
if ($path =~ /\//){
  if ($path =~ /^\//){
    $path =~ /^((\/[^\/]+){1,}\/)[^\/]+$/;
    $path = $1;
    }
  else {
    $path =~ /^(([^\/]+\/){1,})[^\/]+$/;
    my $path_b = $1;
    my $path_a = `pwd`;
    chop($path_a);
    $path = $path_a."/".$path_b;
    }
  }
else{
  $path = `pwd`;
  chop($path);
  $path.="/";
  }
$path =~ s/\/\//\//g;



print "\n$path\n";

: DD

Você está procurando este:?

my $thisfile = $1 if $0 =~
/\\([^\\]*)$|\/([^\/]*)$/;

print "You are running $thisfile
now.\n";

A saída será semelhante a este:

You are running MyFileName.pl now.

Ele funciona em Windows e Unix.

use strict ; use warnings ; use Cwd 'abs_path';
    sub ResolveMyProductBaseDir { 

        # Start - Resolve the ProductBaseDir
        #resolve the run dir where this scripts is placed
        my $ScriptAbsolutPath = abs_path($0) ; 
        #debug print "\$ScriptAbsolutPath is $ScriptAbsolutPath \n" ;
        $ScriptAbsolutPath =~ m/^(.*)(\\|\/)(.*)\.([a-z]*)/; 
        $RunDir = $1 ; 
        #debug print "\$1 is $1 \n" ;
        #change the \'s to /'s if we are on Windows
        $RunDir =~s/\\/\//gi ; 
        my @DirParts = split ('/' , $RunDir) ; 
        for (my $count=0; $count < 4; $count++) {   pop @DirParts ;     }
        my $ProductBaseDir = join ( '/' , @DirParts ) ; 
        # Stop - Resolve the ProductBaseDir
        #debug print "ResolveMyProductBaseDir $ProductBaseDir is $ProductBaseDir \n" ; 
        return $ProductBaseDir ; 
    } #eof sub 

O problema com __FILE__ é que ele irá imprimir o caminho núcleo módulo ".pm" não necessariamente o ".cgi" ou ".pl" caminho do script que está sendo executado. Eu acho que depende de qual é sua meta.

Parece-me que Cwd apenas precisa de ser actualizada para mod_perl. Aqui está a minha sugestão:

my $path;

use File::Basename;
my $file = basename($ENV{SCRIPT_NAME});

if (exists $ENV{MOD_PERL} && ($ENV{MOD_PERL_API_VERSION} < 2)) {
  if ($^O =~/Win/) {
    $path = `echo %cd%`;
    chop $path;
    $path =~ s!\\!/!g;
    $path .= $ENV{SCRIPT_NAME};
  }
  else {
    $path = `pwd`;
    $path .= "/$file";
  }
  # add support for other operating systems
}
else {
  require Cwd;
  $path = Cwd::getcwd()."/$file";
}
print $path;

Por favor, adicione todas as sugestões.

Sem qualquer módulos externos, válido por shell, funciona bem mesmo com' ../':

my $self = `pwd`;
chomp $self;
$self .='/'.$1 if $0 =~/([^\/]*)$/; #keep the filename only
print "self=$self\n";

teste:

$ /my/temp/Host$ perl ./host-mod.pl 
self=/my/temp/Host/host-mod.pl

$ /my/temp/Host$ ./host-mod.pl 
self=/my/temp/Host/host-mod.pl

$ /my/temp/Host$ ../Host/./host-mod.pl 
self=/my/temp/Host/host-mod.pl

O problema com apenas usando dirname(__FILE__) é que ele não segue links simbólicos. Eu tive que usar isso para o meu script para seguir o link simbólico para o local do arquivo real.

use File::Basename;
my $script_dir = undef;
if(-l __FILE__) {
  $script_dir = dirname(readlink(__FILE__));
}
else {
  $script_dir = dirname(__FILE__);
}

Todas as soluções livre de biblioteca na verdade, não trabalho por mais de algumas maneiras de escrever um caminho (pense ../ ou /bla/x/../bin/./x/../ etc. My olhares solução como abaixo Eu tenho uma peculiaridade:. Eu não tenho a menor idéia por que eu tenho que correr as substituições duas vezes Se eu não fizer isso, eu recebo uma espúria "./" ou "../" Além de.. que, ao que parece bastante robusto para mim.

  my $callpath = $0;
  my $pwd = `pwd`; chomp($pwd);

  # if called relative -> add pwd in front
  if ($callpath !~ /^\//) { $callpath = $pwd."/".$callpath; }  

  # do the cleanup
  $callpath =~ s!^\./!!;                          # starts with ./ -> drop
  $callpath =~ s!/\./!/!g;                        # /./ -> /
  $callpath =~ s!/\./!/!g;                        # /./ -> /        (twice)

  $callpath =~ s!/[^/]+/\.\./!/!g;                # /xxx/../ -> /
  $callpath =~ s!/[^/]+/\.\./!/!g;                # /xxx/../ -> /   (twice)

  my $calldir = $callpath;
  $calldir =~ s/(.*)\/([^\/]+)/$1/;

Nenhum dos "top" respostas foram certo para mim. O problema com o uso FindBin '$ Bin' ou Cwd é que eles retornam caminho absoluto com todos os links simbólicos resolvidos. No meu caso eu precisava o caminho exato com links simbólicos presentes - o mesmo que o comando retorna Unix "pwd" e não "-P pwd". A função a seguir fornece a solução:

sub get_script_full_path {
    use File::Basename;
    use File::Spec;
    use Cwd qw(chdir cwd);
    my $curr_dir = cwd();
    chdir(dirname($0));
    my $dir = $ENV{PWD};
    chdir( $curr_dir);
    return File::Spec->catfile($dir, basename($0));
}

O que há de errado com $^X?

#!/usr/bin/env perl<br>
print "This is executed by $^X\n";

iria dar-lhe o caminho completo para o binário Perl sendo usado.

Evert

Em * nix, você provavelmente tem o comando "whereis", que procura o seu $ PATH procura de um binário com um determinado nome. Se $ 0 não contém o nome completo do caminho, correndo whereis $ scriptname e salvar o resultado em uma variável deve dizer-lhe onde o script está localizado.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top