मुझे एक पर्ल स्क्रिप्ट का पूरा रास्ता कैसे मिल रहा है जो निष्पादित हो रहा है?


168

मेरे पास पर्ल स्क्रिप्ट है और निष्पादन के दौरान स्क्रिप्ट का पूरा पथ और फ़ाइल नाम निर्धारित करने की आवश्यकता है। मुझे पता चला कि कैसे आप स्क्रिप्ट कॉल के आधार पर $0भिन्न होता है और कभी-कभी होता है fullpath+filenameऔर कभी कभी बस filename। क्योंकि वर्किंग डायरेक्टरी अलग-अलग हो सकती है और मैं fullpath+filenameस्क्रिप्ट का मज़बूती से इस्तेमाल करने का तरीका नहीं सोच सकता ।

किसी को हल मिल गया?

जवाबों:


251

कुछ तरीके हैं:

  • $0 वर्तमान में कार्यशील निर्देशिका के अनुसार POSIX द्वारा प्रदान की गई स्क्रिप्ट है, यदि स्क्रिप्ट CWD के नीचे या नीचे है
  • साथ ही, cwd(), getcwd()और abs_path()द्वारा प्रदान की जाती हैं Cwdमॉड्यूल और आपको बता जहां स्क्रिप्ट से चलाया जा रहा है
  • मॉड्यूल & वैरिएबल FindBinप्रदान करता है जो आमतौर पर निष्पादित स्क्रिप्ट का मार्ग होता है; यह मॉड्यूल भी प्रदान करता है और स्क्रिप्ट का नाम है$Bin$RealBin$Script$RealScript
  • __FILE__ वास्तविक फ़ाइल है कि पर्ल दुभाषिया संकलन के दौरान अपने पूर्ण पथ सहित से संबंधित है।

मैंने पहले तीन ( $0, Cwdमॉड्यूल और FindBinमॉड्यूल) को mod_perlशानदार तरीके से असफल देखा है , जैसे कि बेकार आउटपुट '.'या एक खाली स्ट्रिंग का उत्पादन करना । ऐसे वातावरण में, मैं मॉड्यूल __FILE__का उपयोग करके उस से पथ का उपयोग करता हूं और प्राप्त करता हूं File::Basename:

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

2
यह वास्तव में सबसे अच्छा समाधान है, खासकर यदि आपके पास पहले से ही $ 0
Caterham

8
ऐसा लगता है कि abs_path को _____FILE_____ के साथ उपयोग करने की आवश्यकता है क्योंकि इसमें केवल पथ के साथ नाम शामिल हो सकता है।
आफ्टरशॉक

6
@vicTROLLA शायद इसलिए क्योंकि इस उत्तर से सबसे बड़ी सिफारिश (dirname का उपयोग करके __FILE__) काफी उम्मीद के मुताबिक काम नहीं करती है? मैं उस सापेक्ष पथ के साथ समाप्त होता हूं जहां से स्क्रिप्ट निष्पादित की गई थी, जबकि स्वीकृत जवाब मुझे पूर्ण निरपेक्ष मार्ग देता है।
इजाकाता

10
dirname(__FILE__)सिमलिंक का पालन नहीं करता, इसलिए यदि आप निष्पादन योग्य फ़ाइल और जहां लिंक किए गए स्थान को स्थापित करने की जांच करनी है में कुछ अन्य फ़ाइल का स्थान खोजने के लिए उम्मीद कर रहा if( -l __FILE__)है और फिर dirname(readlink(__FILE__))
डेविड जीज

3
@IliaRostovtsev आप पा सकते हैं जब एक मॉड्यूल पहली बार इस झुकाव के साथ मानक मॉड्यूल में शामिल किया गया था perl -e 'use Module::CoreList; print Module::CoreList->first_release("File::Basename");'; echo:। उसके लिए File::Basenameपर्ल 5.0.0 था, जिसे 90 के दशक के अंत में रिलीज़ किया गया था - मुझे लगता है कि यह अब तक उपयोग करने के लिए बचा है।
ड्रू स्टीफंस

145

$ 0 आम तौर पर आपके कार्यक्रम का नाम है, तो इस बारे में कैसे?

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

मुझे लगता है कि यह काम करना चाहिए क्योंकि abs_path जानता है कि क्या आप किसी रिश्तेदार या निरपेक्ष मार्ग का उपयोग कर रहे हैं।

अपडेट इस वर्ष पढ़ने वाले किसी भी व्यक्ति के लिए, आपको ड्रू का उत्तर पढ़ना चाहिए । यह मेरे से बहुत बेहतर है।


11
छोटी टिप्पणी, खिड़कियों पर सक्रिय परिधि पर $ 0 में आम तौर पर बैकस्लैश होते हैं और abs_path आगे की स्लैश लौटाता है, इसलिए एक त्वरित "tr / \ / \\ /;" इसे ठीक करने की आवश्यकता थी।
क्रिस मैडेन

3
जोड़ना चाहता था कि वहाँ एक है realpath, जो एक पर्यायवाची है abs_path, अगर आप कोई
गैर

@ क्रिस, क्या आपने Cwd मॉड्यूल मेंटेनर को बग रिपोर्ट किया है? यह विंडोज गोद लेने की बग जैसा लगता है।
ज़नीक

1
अन्य समस्या मेरे पास है: perl -e 'use Cwd "abs_path";print abs_path($0);' प्रिंट/tmp/-e
leonbloy

2
जब आप एक स्क्रिप्ट इनलाइन (साथ -e) निष्पादित करते हैं, तो मेरा मानना ​​है कि पर्ल आपकी इनलाइन स्क्रिप्ट को संग्रहीत करने के लिए एक अस्थायी फ़ाइल बनाता है। आपके मामले में स्थान जैसा दिखता है, है /tmp। आपको परिणाम के होने की क्या उम्मीद थी?
ग्रीनजाइंट


16

मुझे लगता है कि आप जिस मॉड्यूल की तलाश कर रहे हैं, वह FindBin है:

#!/usr/bin/perl
use FindBin;

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

11

आप FindBin , Cwd , फ़ाइल :: बेसनेम , या उनमें से एक संयोजन का उपयोग कर सकते हैं। वे सभी पर्ल आईआईआरसी के आधार वितरण में हैं।

मैंने पूर्व में Cwd का उपयोग किया था:

CWD:

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

@bmdhacks, आप सही कह रहे हैं। अनुमान है, आपने 0 $ नहीं बदले हैं। उदाहरण के लिए आप स्क्रिप्ट शुरू होने पर (इनिशियलाइज़ेशन ब्लॉक में), या कहीं और जब आप $ 0 नहीं बदलते हैं तो आप ऊपर काम करते हैं। लेकिन $ 0 'पीएस' यूनिक्स टूल के तहत दिखाई देने वाली प्रक्रिया विवरण को बदलने का एक शानदार तरीका है :) यह
करेन

9

$0या __FILE__आप चाहते हैं कि क्या करने के लिए पूर्ण पथ हो रही है । एकमात्र परेशानी यह है कि अगर किसी ने किया था chdir()और $0रिश्तेदार था - तो आपको BEGIN{}किसी भी आश्चर्य को रोकने के लिए पूर्ण पथ प्राप्त करने की आवश्यकता है ।

FindBin$PATHकुछ मिलान करने के लिए एक बेहतर और चारों ओर घूमने की कोशिश करता है basename($0), लेकिन ऐसे समय होते हैं जब वह दूर-आश्चर्य की चीजें करता है (विशेषकर: जब cwd में फ़ाइल आपके सामने "सही है")।

File::Fuहै File::Fu->program_nameऔर इसके File::Fu->program_dirलिए।


क्या यह वास्तव में संभावना है कि किसी को भी chdir()संकलन समय पर (स्थायी रूप से) इतनी मूर्खता होगी ?
सामब

बस स्क्रिप्ट शुरू होने पर वर्तमान डायर और $ 0 के आधार पर सभी काम करते हैं।
ज़नीक

7

कुछ छोटी पृष्ठभूमि:

दुर्भाग्य से यूनिक्स एपीआई निष्पादन योग्य के लिए पूर्ण पथ के साथ एक रनिंग प्रोग्राम प्रदान नहीं करता है। वास्तव में, आपका निष्पादित करने वाला कार्यक्रम उस क्षेत्र में जो कुछ भी चाहता है वह प्रदान कर सकता है जो सामान्य रूप से आपके कार्यक्रम को बताता है कि वह क्या है। संभावित उम्मीदवारों को खोजने के लिए सभी जवाबों को इंगित करने के रूप में सभी उत्तर हैं। लेकिन पूरे फाइल सिस्टम को खोजने में कुछ भी कमी हमेशा काम नहीं करेगी, और यहां तक ​​कि अगर निष्पादन योग्य स्थानांतरित या हटा दिया जाता है, तो भी यह विफल हो जाएगा।

लेकिन आप पर्ल निष्पादन योग्य नहीं चाहते हैं, जो कि वास्तव में चल रहा है, लेकिन वह स्क्रिप्ट निष्पादित कर रहा है। और पर्ल को यह जानने की जरूरत है कि स्क्रिप्ट को कहां खोजना है। यह इसे स्टोर करता है __FILE__, जबकि $0यह यूनिक्स एपीआई से है। यह अभी भी एक सापेक्षिक मार्ग हो सकता है, इसलिए मार्क के सुझाव को लें और इसे अपने साथ जोड़ लेंFile::Spec->rel2abs( __FILE__ );


__FILE__अभी भी मुझे एक सापेक्ष मार्ग देता है। अर्थात '।'।
felwithe

6

आपने कोशिश की है:

$ENV{'SCRIPT_NAME'}

या

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

यह वास्तव में इस बात पर निर्भर करता है कि इसे कैसे बुलाया जा रहा है और यदि यह सीजीआई है या सामान्य शेल से चलाया जा रहा है, आदि।


$ ENV {'SCRIPT_NAME'} खाली है जब स्क्रिप्ट कंसोल पर चल रही है
Putnik

बुरा विचार क्योंकि SCRIPT_NAME एनवायरमेंट आपके द्वारा उपयोग किए जा रहे शेल पर निर्भर है। यह पूरी तरह से विंडोज़ cmd.exe के साथ असंगत है, और जब आप अन्य बायनेरिज़ से स्क्रिप्ट सीधे कॉल करते हैं तो असंगत। इस वॉरएबल सेट होने की कोई वारंटी नहीं है। उपरोक्त तरीके बहुत अधिक प्रयोग करने योग्य हैं।
ज़नीक

6

अपनी स्क्रिप्ट वाली निर्देशिका का मार्ग प्राप्त करने के लिए मैंने पहले से दिए गए उत्तरों के संयोजन का उपयोग किया।

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

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

2

perlfaq8rel2abs() फ़ंक्शन का उपयोग करने के साथ एक बहुत ही समान प्रश्न का उत्तर देता है $0। वह फ़ंक्शन फ़ाइल :: Spec में पाया जा सकता है।


2

बाहरी मॉड्यूल का उपयोग करने की कोई आवश्यकता नहीं है, केवल एक पंक्ति के साथ आपके पास फ़ाइल नाम और सापेक्ष पथ हो सकता है। यदि आप मॉड्यूल का उपयोग कर रहे हैं और स्क्रिप्ट निर्देशिका के सापेक्ष पथ को लागू करने की आवश्यकता है, तो सापेक्ष पथ पर्याप्त है।

$0 =~ m/(.+)[\/\\](.+)$/;
print "full path: $1, file name: $2\n";

यह स्क्रिप्ट का उचित पूर्ण पथ प्रदान नहीं करता है यदि आप इसे "./mcriptcript.pl" की तरह चलाते हैं, जैसा कि यह केवल दिखाएगा। " बजाय। लेकिन मुझे यह समाधान अभी भी पसंद है।
केव

1
#!/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";

: डीडी


4
कृपया कोड के साथ जवाब न दें। कृपया समझाएं कि यह सही उत्तर क्यों है।
ली टेलर

1

क्या आप इसके लिए देख रहे हैं: "

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

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

आउटपुट इस तरह दिखेगा:

You are running MyFileName.pl now.

यह विंडोज और यूनिक्स दोनों पर काम करता है।


0
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 

हालांकि स्रोत-केवल उत्तर उपयोगकर्ता के प्रश्न को हल कर सकते हैं, यह उन्हें यह समझने में मदद नहीं करता है कि यह क्यों काम करता है। आपने उपयोगकर्ता को मछली दी है, लेकिन इसके बजाय आपको उन्हें मछली कैसे सिखाना चाहिए।
द टिन मैन

0

इसके साथ समस्या __FILE__यह है कि यह कोर मॉड्यूल ".pm" पथ को मुद्रित करेगा जरूरी नहीं कि ".cgi" या ".pl" स्क्रिप्ट पथ जो चल रहा है। मुझे लगता है कि यह इस बात पर निर्भर करता है कि आपका लक्ष्य क्या है।

यह मुझे लगता है कि Cwdबस mod_perl के लिए अद्यतन करने की आवश्यकता है। यहाँ मेरा सुझाव है:

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;

कृपया कोई सुझाव जोड़ें।


0

शेल के लिए मान्य किसी भी बाहरी मॉड्यूल के बिना, '../' के साथ भी अच्छा काम करता है:

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

परीक्षा:

$ /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

जब आप सिमलिंक कहते हैं तो क्या होगा? Cwd इस मामले में उत्कृष्ट काम करता है।
ज़नीक

0

सिर्फ उपयोग करने के साथ समस्या dirname(__FILE__)यह है कि यह सिमलिंक का पालन नहीं करता है। मुझे अपनी स्क्रिप्ट के लिए इसका उपयोग वास्तविक फ़ाइल स्थान पर सिम्लिंक का पालन करने के लिए करना था।

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

0

सभी पुस्तकालय-मुक्त समाधान वास्तव में पथ लिखने के लिए कुछ तरीकों से अधिक काम नहीं करते हैं (विचार करें .. / या /bla/x/../bin/./x/../ आदि) मेरा समाधान दिखता है नीचे। मेरे पास एक क्वर्की है: मेरे पास यह बेहूदा विचार नहीं है कि मुझे दो बार रिप्लेसमेंट क्यों चलाना है। अगर मैं नहीं करता, तो मुझे एक शानदार "./" या "../" मिलता है। इसके अलावा, यह मुझे काफी मजबूत लगता है।

  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/;

0

कोई भी "शीर्ष" उत्तर मेरे लिए सही नहीं था। फाइंडबिन '$ बिन' या सीडब्ल्यूडी का उपयोग करने के साथ समस्या यह है कि वे सभी प्रतीकात्मक लिंक के साथ निरपेक्ष पथ पर लौटते हैं। मेरे मामले में मुझे वर्तमान में प्रतीकात्मक लिंक के साथ सटीक मार्ग की आवश्यकता थी - रिटर्न यूनिक्स कमांड "pwd" के समान और "pwd -P" नहीं। निम्नलिखित फ़ंक्शन समाधान प्रदान करता है:

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));
}

0

Windows का उपयोग कर dirnameऔर abs_pathसाथ में मेरे लिए सबसे अच्छा काम किया।

use File::Basename;
use Cwd qw(abs_path);

# absolute path of the directory containing the executing script
my $abs_dirname = dirname(abs_path($0));
print "\ndirname(abs_path(\$0)) -> $abs_dirname\n";

यहाँ पर क्यों:

# this gives the answer I want in relative path form, not absolute
my $rel_dirname = dirname(__FILE__); 
print "dirname(__FILE__) -> $rel_dirname\n"; 

# this gives the slightly wrong answer, but in the form I want 
my $full_filepath = abs_path($0);
print "abs_path(\$0) -> $full_filepath\n";

-2

इसमें गलत क्या है $^X?

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

क्या आप उपयोग किए जा रहे पर्ल बाइनरी को पूरा रास्ता देंगे।

एवर्ट


1
यह आवश्यक स्क्रिप्ट के लिए पर्ल बाइनरी पथ को पथ देता है
पुटनिक

-5

* निक्स पर, आपको "ह्वाइसिस" कमांड की संभावना है, जो आपके $ पीएटीएच को किसी दिए गए नाम के साथ द्विआधारी की खोज करता है। यदि $ 0 में पूर्ण पथ नाम नहीं है, जिसमें $ scriptname चल रहा है और परिणाम को एक चर में सहेजकर आपको यह बताना चाहिए कि स्क्रिप्ट कहाँ स्थित है।


यही कारण है कि काम नहीं, के रूप में $ 0 भी एक रिश्तेदार पथ फाइल करने के लिए वापस आ जाएगी सकता है: ../perl/test.pl
Lathan

यदि निष्पादन योग्य स्क्रिप्ट पथ से बाहर है तो क्या होगा?
ज़निक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.