রুবিতে ব্যবহারের অনুরোধ জানানো কমান্ডটির নাম আমি কীভাবে পেতে পারি?


83

আমি কিছুক্ষণ আগে একটি সুন্দর ছোট রুবি স্ক্রিপ্ট লিখেছিলাম যে আমি বরং পছন্দ করি। আমি যুক্তিগুলির যথাযথ সংখ্যাটি পরীক্ষা করে এর দৃ its়তা উন্নত করতে চাই:

if ARGV.length != 2 then
  puts "Usage: <command> arg1 arg2"
end

অবশ্যই এটি সিউডোকোড। যাইহোক, C অথবা C ++ আমি ব্যবহার করতে পারে argv[0]নাম পেতে কাছে সেই ব্যবহারকারীর আমার আদেশ পেতে ব্যবহার করা হয়, কিনা তারা এটা পছন্দ নামক ./myScript.rbবা myScript.rbবা /usr/local/bin/myScript.rb। রুবিতে, আমি জানি ARGV[0]এটি প্রথম সত্য যুক্তি, এবং ARGVকমান্ডের নামটি ধারণ করে না। আমি এটি পেতে পারে যে কোন উপায় আছে?

উত্তর:


149

রুবি আমাদের কাছে লিখিত স্ক্রিপ্টটির নাম দেওয়ার তিনটি উপায় রয়েছে:

#!/usr/bin/env ruby

puts "$0            : #{$0}"
puts "__FILE__      : #{__FILE__}"
puts "$PROGRAM_NAME : #{$PROGRAM_NAME}"

সেই কোডটিকে "টেস্ট.আরবি" হিসাবে সংরক্ষণ করা এবং এটি বেশ কয়েকটি উপায়ে কল করা দেখায় যে স্ক্রিপ্টটি ওএস দ্বারা এটি পাস করার সাথে সাথে নামটি পেয়েছিল। একটি স্ক্রিপ্ট কেবল ওএস যা বলে তা জানে:

$ ./test.rb 
$0            : ./test.rb
__FILE__      : ./test.rb
$PROGRAM_NAME : ./test.rb

$ ~/Desktop/test.rb 
$0            : /Users/ttm/Desktop/test.rb
__FILE__      : /Users/ttm/Desktop/test.rb
$PROGRAM_NAME : /Users/ttm/Desktop/test.rb

$ /Users/ttm/Desktop/test.rb 
$0            : /Users/ttm/Desktop/test.rb
__FILE__      : /Users/ttm/Desktop/test.rb
$PROGRAM_NAME : /Users/ttm/Desktop/test.rb

~দ্বিতীয় উদাহরণে OME HOM এর শর্টকাট ব্যবহার করে এটিকে কল করা তৃতীয় উদাহরণের সাথে মিলে ওএসকে প্রসারিত পথ দিয়ে প্রতিস্থাপন করে। সমস্ত ক্ষেত্রে ওএস এর মধ্যে যা পেরেছে।

শক্ত এবং নরম উভয় লিঙ্ক ব্যবহার করে ফাইলের সাথে লিঙ্ক করা সুসংগত আচরণ দেখায়। আমি test1.rb এর জন্য একটি হার্ড লিঙ্ক এবং টেস্ট 2.rb এর জন্য একটি নরম লিঙ্ক তৈরি করেছি:

$ ./test1.rb 
$0            : ./test1.rb
__FILE__      : ./test1.rb
$PROGRAM_NAME : ./test1.rb

$ ./test2.rb 
$0            : ./test2.rb
__FILE__      : ./test2.rb
$PROGRAM_NAME : ./test2.rb

ruby test.rbস্ক্রিপ্ট নামের যে কোনও প্রকারের সাথে প্রবর্তন করা ধারাবাহিক ফলাফল দেয়।

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

$0এবং __FILE__কিছু ছোট পার্থক্য আছে তবে একক স্ক্রিপ্টগুলির জন্য সেগুলি সমতুল্য।

puts File.basename($0)

সেখানে ব্যবহার করার কিছু সুবিধা হয় File.basename, File.extnameএবং File.dirnameপদ্ধতি সুইট। basenameএকটি alচ্ছিক প্যারামিটার নেয় যা স্ট্রিপটি এক্সটেনশন হয়, তাই আপনার যদি এক্সটেনশন ছাড়াই কেবল বেস নামটির প্রয়োজন হয়

File.basename($0, File.extname($0)) 

চাকাটিকে পুনরায় উদ্ভাবন করা বা পরিবর্তনশীল দৈর্ঘ্য বা অনুপস্থিত এক্সটেনশনগুলির সাথে মোকাবিলা না করে বা .rb.txtউদাহরণস্বরূপ ভুলভাবে এক্সটেনশন চেইনগুলি কেটে ফেলার সম্ভাবনা : "

ruby-1.9.2-p136 :004 > filename = '/path/to/file/name.ext'
 => "/path/to/file/name.ext" 
ruby-1.9.2-p136 :005 > File.basename(filename, File.extname(filename))
 => "name" 
ruby-1.9.2-p136 :006 > filename = '/path/to/file/name.ext' << '.txt'
 => "/path/to/file/name.ext.txt" 
ruby-1.9.2-p136 :007 > File.basename(filename, File.extname(filename))
 => "name.ext" 

খুব সম্পূর্ণ উত্তরের জন্য ধন্যবাদ!
অ্যাডাম_0

4
মনে রাখবেন যে আপনি যদি অন্তর্ভুক্ত স্ক্রিপ্টে প্রস্তাবিত বিকল্পগুলি 'আবশ্যক' বা 'আবশ্যক_ সম্পর্কিত সম্পর্কিত ব্যবহার করে থাকেন তবে আলাদা আচরণ রয়েছে। $ 0 এবং $ PROGRAM_NAME ব্যবহার করে কলিং স্ক্রিপ্টটির নাম ফিরে আসে। আশেপাশের ডাবল আন্ডারবারগুলির সাথে ফাইল বিকল্পটি ব্যবহার করা (আপনি কীভাবে কোনও মন্তব্যে এটি ফর্ম্যাট করবেন?) অন্তর্ভুক্ত স্ক্রিপ্টটির নাম ফিরিয়ে দেয়।
মাইক 663

18

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

আমার বিরক্ত যে ছিল $0বা $PROGRAM_NAMEসত্যিই কি ব্যবহারকারী সম্পর্কে সঠিক তথ্য রাখা হয়নি টাইপ করা । যদি আমার রুবি স্ক্রিপ্টটি কোনও PATH ফোল্ডারে থাকে এবং ব্যবহারকারী নির্বাহযোগ্য নাম প্রবেশ করায় (যেমন কোনও পথের সংজ্ঞা যেমন ./scriptবা না /bin/script), এটি সর্বদা মোট পথে প্রসারিত হবে।

আমি ভেবেছিলাম এটি একটি রুবির ঘাটতি, তাই পাইথন এবং সেখানে আমার চাগ্রিনের সাথেও আমি একই চেষ্টা করেছি, এটি কোনও আলাদা নয়।

একটি বন্ধু আমাকে সন্ধান করার জন্য একটি হ্যাক প্রস্তাব real thingকরেছিল /proc/self/cmdline, এবং ফলাফলটি ছিল: [ruby, /home/danyel/bin/myscript, arg1, arg2...](নাল-চর দ্বারা পৃথক)। এখানকার খলনায়ক হ'ল execve(1)এটি যখন কোনও অনুবাদকের কাছে পৌঁছে দেয় তখন মোট পাথের পথটি প্রসারিত করে।

সি প্রোগ্রাম উদাহরণ:

#include <stdlib.h>
#include <unistd.h>

extern char** environ;
int main() {
  char ** arr = malloc(10 * sizeof(char*));
  arr[0] = "myscript";
  arr[1] = "-h";
  arr[2] = NULL;
  execve("/home/danyel/bin/myscript", arr, environ);
}

আউটপুট: `ব্যবহার: / হোম / ড্যানিয়েল / বিন / ম্যাসক্রিপ্ট ফাইল ...

এটি প্রমাণ করার জন্য যে এটি সত্যই কোনও execveজিনিস এবং বাশ থেকে নয়, আমরা একটি ডামি ইন্টারপ্রেটার তৈরি করতে পারি যা এতে প্রেরিত যুক্তিগুলি ছাপানো ছাড়া কিছুই করে না:

// interpreter.c
int main(int argc, const char ** argv) {
  while(*argv)
    printf("%s\n", *(argv++));
}

আমরা এটি সংকলন করে একটি পাথ ফোল্ডারে রেখেছি (বা শেবাংয়ের পরে পুরো পথটি রেখেছি) এবং এতে একটি ডামি স্ক্রিপ্ট তৈরি করি ~/bin/myscript/

#!/usr/bin/env interpreter
Hi there!

এখন, আমাদের main.c এ:

#include <stdlib.h>

extern char** environ;
int main() {
  char ** arr = malloc(10 * sizeof(char*));
  arr[0] = "This will be totally ignored by execve.";
  arr[1] = "-v";
  arr[2] = "/var/log/apache2.log";
  arr[3] = NULL;
  execve("/home/danyel/bin/myscript", arr, environ);
}

সংকলন এবং চলমান ./main: দোভাষী / হোম / ড্যানিয়েল / বিন / মাইক্রিপ্ট -v /var/log/apache2.log

সম্ভবত এটির পিছনে কারণটি হ'ল যদি স্ক্রিপ্টটি আপনার পাঠ্যপথের মধ্যে থাকে এবং পুরো পথটি সরবরাহ না করা হত , দোভাষী অনুবাদক এটিকে একটি No such fileত্রুটি হিসাবে স্বীকৃতি দেবেন যা আপনি যদি করেন তবে: ruby myrubyscript --options arg1এবং আপনি সেই স্ক্রিপ্টটির ফোল্ডারে নেই ।


3

বর্তমানে সম্পাদিত হওয়া ফাইলের নামটি ব্যবহার করুন $0বা $PROGRAM_NAMEপান।


এটি আমাকে পুরো পথ দেয়। আমি ব্যবহারকারী কী লিখেছে তা জানতে চাই। উদাহরণস্বরূপ, যদি আমার কাছে থাকে /usr/local/bin/myScriptএবং /usr/local/binআমার মধ্যে থাকে $PATHএবং আমি কেবল টাইপ myScriptকরি তবে আমি /usr/local/bin/myScriptপেয়েছি$0
adam_0

4
কীভাবে $0.split("/").last?
পিয়েরোট্লেফৌ

7
আমি প্রোগ্রামটির নামটি জিজ্ঞাসা করছি না, আমার অর্থটি হ'ল আমি প্রোগ্রামটি চালানোর জন্য ব্যবহারকারী যা টাইপ করেছেন ঠিক সেটাই চাই। যদি তারা টাইপ করে তবে ./myScriptআমি একটি পরিবর্তনশীল চাই যা আমাকে দেয় ./myScript। যদি তারা টাইপ করে /usr/bin/local/myScript, আমি ঠিক এটি চাই। ইত্যাদি
অ্যাডাম_0

3

এটি আপনার প্রশ্নের পুরো উত্তর নয়, তবে মনে হচ্ছে আপনি একটি চাকা পুনরুদ্ধার করছেন। এ optparse গ্রন্থাগার। এটি আপনাকে কমান্ড লাইন সুইচগুলি, আর্গুমেন্টগুলি ইত্যাদির সংজ্ঞা দিতে দেয় এবং এটি আপনার জন্য সমস্ত ভারী উত্তোলন করবে।


4
ধন্যবাদ, তবে জটিল কিছু করার দরকার নেই। আমি বলতে চাইছি, আমার কাছে কেবল 2 টি যুক্তি রয়েছে, তাই এতটা ওয়ারেন্ট করার পক্ষে খুব সহজ কেস।
অ্যাডাম_0
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.