কার্যকর করা পার্ল স্ক্রিপ্টের পুরো পথটি কীভাবে পাব?


168

আমার পার্ল স্ক্রিপ্ট রয়েছে এবং সম্পাদনার সময় স্ক্রিপ্টের পুরো পথ এবং ফাইলের নাম নির্ধারণ করা দরকার। আমি আবিষ্কার করেছি যে কিভাবে আপনি স্ক্রিপ্ট কল উপর নির্ভর করে $0পরিবর্তিত হয় এবং কখনও কখনও রয়েছে fullpath+filenameএবং কখনও কখনও শুধু filename। কারণ ডিরেক্টরি ডিরেক্টরি পরিবর্তিত হতে পারে পাশাপাশি আমি fullpath+filenameস্ক্রিপ্টটি নির্ভরযোগ্যভাবে পাওয়ার কোনও উপায় ভাবতে পারি না ।

কেউ সমাধান পেয়েছেন?

উত্তর:


251

কয়েকটি উপায় আছে:

  • $0 স্ক্রিপ্টটি সিডব্লিউডির নীচে বা নীচে থাকলে পজিক্সের সরবরাহ হিসাবে বর্তমানে চলমান স্ক্রিপ্ট হ'ল
  • উপরন্তু, 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
কেটারহাম

8
দেখে মনে হচ্ছে অ্যাবস_পথটি _____FILE_____ এর সাথে ব্যবহার করা দরকার কারণ এতে কেবল পথের সাথে নাম থাকতে পারে।
আফটারশক

6
@ ভিকট্রোল্লা সম্ভবত কারণ এই উত্তরটি থেকে সবচেয়ে বড় সুপারিশটি (এর সাথে নাম ব্যবহার করে __FILE__) প্রত্যাশার মতো কাজ করে না? স্ক্রিপ্টটি কার্যকর করা হয়েছিল সেখান থেকে আমি আপেক্ষিক পথটি শেষ করি, যখন স্বীকৃত উত্তরটি আমাকে পুরো পরম পথ দেয়।
ইজকাটা

10
dirname(__FILE__)symlinks অনুসরণ না, তাই আপনি যদি এক্সিকিউটেবল ফাইল এবং যেখানে লিঙ্ক অবস্থান ইনস্টল চেক করতে হবে কিছু অন্যান্য ফাইলের অবস্থান খুঁজে প্রত্যাশী 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, যা 90s এর দশকের শেষের দিকে প্রকাশিত হয়েছিল think আমি মনে করি এটি এতক্ষণে ব্যবহার করা নিরাপদ।
ড্রিউ স্টিফেন্স

145

Program 0 সাধারণত আপনার প্রোগ্রামের নাম, তবে এটি কীভাবে হবে?

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

আমার কাছে মনে হচ্ছে এটি অ্যাবস_পথ হিসাবে কাজ করা উচিত জানে যে আপনি কোনও আপেক্ষিক বা পরম পথ ব্যবহার করছেন কিনা knows

আপডেট এই বছর পরে যে কারও জন্য পড়া, আপনি ড্র এর উত্তর পড়া উচিত । এটা আমার চেয়ে অনেক ভাল


11
উইন্ডোজ on 0 এ অ্যাক্টিস্টেট পার্লের উপর ছোট মন্তব্যটি সাধারণত ব্যাকস্ল্যাশগুলি থাকে এবং অ্যাবস_প্যাথ ফরোয়ার্ড স্ল্যাশগুলি উপস্থিত করে, তাই একটি দ্রুত "tr / \ // \\ /"; এটি ঠিক করার প্রয়োজন ছিল।
ক্রিস ম্যাডেন

3
যোগ করতে চেয়েছিলেন যে সেখানে একটি আছে realpath, যা একটি প্রতিশব্দ abs_path, যদি আপনি নো-আন্ডারস্কোর নামটি পছন্দ করেন
ভলিউরন

@ ক্রিস, আপনি কি সিডডির মডিউল রক্ষণাবেক্ষণকারীকে বাগ রিপোর্ট করেছিলেন? দেখে মনে হচ্ছে উইন্ডোজ অ্যাডোপশন বাগ।
Znik

1
আমার অন্যান্য সমস্যা আছে: perl -e 'use Cwd "abs_path";print abs_path($0);' প্রিন্ট/tmp/-e
লেওনব্লায়

2
@ লেওনব্লয় যখন আপনি কোনও স্ক্রিপ্ট ইনলাইন (সাথে -e) সম্পাদন করেন , আমি বিশ্বাস করি পার্ল আপনার ইনলাইন স্ক্রিপ্টটি সংরক্ষণ করার জন্য একটি টেম্প ফাইল তৈরি করে। আপনার অবস্থার মতো অবস্থানটি মনে হচ্ছে /tmp। আপনি ফলাফলটি কী আশা করেছিলেন?
গ্রিন জায়ান্ট


16

আমি মনে করি আপনি যে মডিউলটি সন্ধান করছেন তা হ'ল ফাইন্ডবিন:

#!/usr/bin/perl
use FindBin;

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

11

আপনি ফাইন্ডবিন , সিডাব্লুডি , ফাইল :: বেসনাম বা সেগুলির সংমিশ্রণ ব্যবহার করতে পারেন। তারা সবাই পার্ল আইআইআরসি-র বেস বিতরণে রয়েছে।

আমি অতীতে সিডব্লিউড ব্যবহার করেছি:

Cwd:

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

@ বিএমড্যাকস, আপনি ঠিক বলেছেন। অনুমানটি হ'ল, আপনি 0 change পরিবর্তন করেন নি $ উদাহরণস্বরূপ আপনি স্ক্রিপ্ট শুরু হওয়ার সাথে সাথেই উপরে কাজ করবেন (সূচনা ব্লকে), বা অন্য কোথাও যখন আপনি $ 0 পরিবর্তন করবেন না। তবে 'পিএস' ইউনিক্স সরঞ্জামের অধীনে দৃশ্যমান প্রক্রিয়া বিবরণ পরিবর্তন করার জন্য $ 0 দুর্দান্ত উপায় :) এটি কারেন প্রক্রিয়া স্থিতি ইত্যাদি প্রদর্শন করতে পারে এটি প্রোগ্রামারের উদ্দেশ্যে নির্ভর করে :)
জেনিক

9

সঠিক পথটি পথ $0বা __FILE__আপনি যা চান তা নয়। কেবলমাত্র সমস্যাটি যদি কেউ এটি করে chdir()এবং এটি $0সম্পর্কিত হয় - তবে BEGIN{}কোনও বিস্ময় রোধ করতে আপনার নিখুঁত পথটি নেওয়া দরকার ।

FindBinএর সাথে $PATHমিলে যাওয়ার জন্য কিছুটা আরও basename($0)ভালভাবে বেঁধে ফেলার চেষ্টা করে , তবে এমন অনেক সময় আসে যখন খুব বেশি অবাক করা জিনিস হয় (বিশেষত: যখন সিডাব্লুডিতে ফাইলটি "আপনার সামনে" থাকে)

File::Fuআছে File::Fu->program_nameএবং File::Fu->program_dirএই জন্য।


এটি কি সম্ভবত সম্ভবত chdir()সংকলনের সময় (স্থায়ীভাবে) হিসাবে এত বোকা হবে ?
স্যামবি

স্ক্রিপ্ট শুরু হওয়ার সাথে সাথে বর্তমান ডিয়ার এবং $ 0 এর উপর ভিত্তি করে কেবল সমস্ত কাজ করুন।
Znik

7

কিছু সংক্ষিপ্ত পটভূমি:

দুর্ভাগ্যক্রমে ইউনিক্স এপিআই এক্সিকিউটেবলের পুরো পথ সহ একটি চলমান প্রোগ্রাম সরবরাহ করে না। প্রকৃতপক্ষে, আপনার সম্পাদনকারী প্রোগ্রামটি ক্ষেত্রটিতে যা যা চায় তা সরবরাহ করতে পারে যা সাধারণত আপনার প্রোগ্রামটি কী তা জানায়। সমস্ত উত্তরগুলি ইঙ্গিত হিসাবে, সম্ভাব্য প্রার্থীদের সন্ধানের জন্য বিভিন্ন হিউরিস্টিকস রয়েছে। তবে পুরো ফাইল সিস্টেমটি অনুসন্ধানের অল্প কিছুতেই সর্বদা কাজ করবে না এবং এক্সিকিউটেবলকে সরানো বা অপসারণ করা গেলেও তা ব্যর্থ হবে।

তবে আপনি পার্ল নির্বাহযোগ্য হতে চান না, এটি যা আসলে চলছে, তবে এটি সম্পাদিত স্ক্রিপ্ট। এবং স্ক্রিপ্টটি এটি কোথায় খুঁজে পেতে হবে তা পার্লের জানা দরকার। এটি এটি সংরক্ষণ করে __FILE__, যখন $0ইউনিক্স এপিআই থেকে। এটি এখনও একটি আপেক্ষিক পথ হতে পারে, তাই মার্কের পরামর্শটি গ্রহণ করুন এবং এর সাথে সারণি করুনFile::Spec->rel2abs( __FILE__ );


__FILE__এখনও আমাকে একটি আপেক্ষিক পথ দেয় অর্থাত্ ''।
felwithe

6

আপনি চেষ্টা করেছেন:

$ENV{'SCRIPT_NAME'}

অথবা

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

এটি কীভাবে বলা হচ্ছে এবং যদি এটি সিজিআই হয় বা কোনও সাধারণ শেল থেকে চালিত হয় ইত্যাদি নির্ভর করে এটি নির্ভর করে etc.


স্ক্রিপ্টটি কনসোলে চলাকালীন $ ENV {'SQLT_NAME' empty খালি রয়েছে
পুতনিক

খারাপ ধারণা কারণ আপনি ব্যবহার করছেন এমন শেলটির উপর স্ক্রিপ্টের পরিবেশ নির্ভরশীল। এটি উইন্ডোজ cmd.exe সহ সম্পূর্ণ অসম্পূর্ণ এবং যখন আপনি অন্য বাইনারি থেকে সরাসরি স্ক্রিপ্ট কল করেন তখন incompatibile। কোন ওয়ারেন্টি নেই এই যুদ্ধযোগ্য সেট করা আছে। উপরের উপায়গুলি অনেক বেশি ব্যবহারযোগ্য।
Znik

6

আমার স্ক্রিপ্টযুক্ত ডিরেক্টরিটিতে পাথ পেতে আমি ইতিমধ্যে দেওয়া উত্তরগুলির সংমিশ্রণটি ব্যবহার করেছি।

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

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

2

পারফ্যাকএক 8rel2abs() ফাংশনটি চালু করার সাথে একটি খুব অনুরূপ প্রশ্নের উত্তর দেয় $0। এই ফাংশনটি ফাইল :: স্পেকে পাওয়া যাবে।


2

বাহ্যিক মডিউলগুলি ব্যবহার করার দরকার নেই, কেবলমাত্র একটি লাইনের সাথে আপনার ফাইলের নাম এবং আপেক্ষিক পথ থাকতে পারে। আপনি যদি মডিউল ব্যবহার করেন এবং স্ক্রিপ্ট ডিরেক্টরি সম্পর্কিত কোনও পাথ প্রয়োগ করতে চান তবে আপেক্ষিক পাথই যথেষ্ট।

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

আপনি যদি এটি "./myscript.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__ হ'ল এটি মূল মডিউলটি ".এমপি" প্রিন্ট করবে যা প্রয়োজনীয়ভাবে ".cgi" বা ".pl" স্ক্রিপ্টের পথটি চলছে running আমার ধারণা এটি আপনার লক্ষ্য কী তার উপর নির্ভর করে।

আমার কাছে মনে হচ্ছে 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 এই ক্ষেত্রেটি নিয়ে দুর্দান্ত কাজ করে।
Znik

0

কেবল ব্যবহারের dirname(__FILE__)ক্ষেত্রে সমস্যাটি হ'ল এটি সিমলিঙ্কগুলি অনুসরণ করে না। আমার স্ক্রিপ্টটির জন্য এটি ব্যবহার করতে হয়েছিল আসল ফাইলের অবস্থানের সিমিলিংক অনুসরণ করতে।

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

0

সমস্ত লাইব্রেরি-মুক্ত সমাধান আসলে কোনও পাথ লেখার জন্য কয়েকটি উপায়ের চেয়ে বেশি কাজ করে না (মনে করুন ../ বা / ব্লা / এক্স /..বিন /।/x/../ ইত্যাদি। আমার সমাধানটি দেখে মনে হচ্ছে নীচে আমার একটি কৌতুক আছে: আমাকে কেন প্রতিস্থাপন দুটি চালাতে হবে তা সম্পর্কে আমার কাছে অবাস্তব ধারণা নেই If আমার কাছে বেশ শক্ত মনে হচ্ছে

  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

"শীর্ষ" কোনও উত্তরই আমার পক্ষে সঠিক ছিল না। ফাইন্ডবিন '$ বিন' বা সিডব্লিউড ব্যবহার করার ক্ষেত্রে সমস্যাটি হ'ল তারা সমাধান করা সমস্ত প্রতীকী লিঙ্কগুলির সাথে নিখুঁত পথে ফিরে আসে। আমার ক্ষেত্রে আমার প্রতীকী লিঙ্কগুলি সহ সঠিক পথের প্রয়োজন ছিল - ইউনিক্স কমান্ড "পিডব্লুডি" হিসাবে প্রদান করে এবং "পিডব্লুডি -পি" নয় returns নিম্নলিখিত ফাংশন সমাধান প্রদান করে:

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

উইন্ডোজ ব্যবহার করে 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";

পার্ল বাইনারি ব্যবহারের জন্য আপনাকে পুরো পথ দেবে।

Evert


1
এটি একটি স্ক্রিপ্টের জন্য পার্ল বাইনারি সহ পাথের পথ দেয়
পুটনিক

-5

* নিক্সে আপনার কাছে সম্ভবত "হোথিস" কমান্ড রয়েছে যা আপনার your PATH প্রদত্ত নামের সাথে বাইনারি খুঁজছে। যদি path 0-তে পুরো পথের নাম না থাকে তবে স্ক্রিপ্টের নামটি চালানো হয় এবং ফলটি একটি ভেরিয়েবলে সংরক্ষণ করাতে আপনাকে স্ক্রিপ্টটি কোথায় রয়েছে তা বলা উচিত।


এতে কাজ না, যেমন $ 0 একটি আপেক্ষিক পাথ ফাইল ফিরে আসবে পারে: ../perl/test.pl
Lathan

এক্সিকিউটেবল স্ক্রিপ্ট পাথের বাইরে থাকলে কী হবে?
জিনিক
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.