2010-10-21 15 views
7

मैं एक प्रोग्राम है जो एक रिश्तेदार पथ का उपयोग कर एक फ़ाइल को खोलता है (उदाहरण के लिए '..')।लिनक्स में इसके सापेक्ष पथ के साथ फ़ाइल कैसे खोलें?

अब समस्या है जब मैं एक निर्देशिका से कार्यक्रम क्रियान्वित, रिश्तेदार पथ कार्यशील निर्देशिका के लिए कार्यक्रम के सापेक्ष लेकिन रिश्तेदार नहीं है,। इस प्रकार, यदि मैं प्रोग्राम को '/ path/to/program/myprog' से शुरू करता हूं तो यह फ़ाइल को ढूंढने में विफल रहता है।

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

+3

लिनक्स पर कार्यक्रम चलाने की की [निर्देशिका संभव डुप्लिकेट ?] (http://stackoverflow.com/questions/737996/directory-of-running-program-on-linux) – ereOn

+1

हालांकि यह प्राप्त करने योग्य होना चाहिए, क्या आप वाकई यह चाहते हैं? लिनक्स पर, प्रत्येक फ़ाइल प्रकार की समर्पित निर्देशिका होती है: कॉन्फ़िगरेशन आमतौर पर '/ etc/'या' ~/.my_program', छवियों और दस्तावेज़ों को '/ usr/share' पर जाता है, और इसी तरह। साथ ही, अधिकांश उपयोगकर्ता आपके प्रोग्राम को वर्तमान निर्देशिका में चलाने की उम्मीद करेंगे। – ereOn

+0

http: //www.dreamincode भी देखें।नेट/फ़ोरम/विषय/98402-निर्देशिका-ऑफ-रनिंग प्रोग्राम/ –

उत्तर

4

तो कार्यक्रम यह अपने आप में नहीं कर रहा है, यह एक बुरा कार्यक्रम है। बुरा कार्यक्रमों बैश पटकथा का एक सा के साथ लिपटे किया जाना चाहिए:

#!/bin/bash 

set -e 
cd $(readlink -f $(dirname $0)) 
exec ./myprog $* 

स्क्रिप्ट ऊपर निर्देशिका जहां यह स्थित है निर्धारित करता है, तो उस निर्देशिका के लिए वर्तमान कार्यशील निर्देशिका बदलता है और वहां से एक कार्यक्रम myprog चलाता सभी मापदंडों पारदर्शी रूप से गुजर । इस प्रकार, आपको इस स्क्रिप्ट को उसी निर्देशिका में रखना होगा जहां आपका प्रोग्राम स्थित है और इसे आपके प्रोग्राम के बजाए चलाएं।

मान लें कि आपके पास स्रोत कोड तक पहुंच है और प्रोग्राम को ठीक कर सकते हैं, फिर प्रोग्राम के स्थान को निर्धारित करने के लिए proc fs का उपयोग करें और फिर पूर्ण पथ का उपयोग करें।

उदाहरण के लिए, /proc/self/exe हमेशा एक सिमलिंक मौजूदा प्रक्रिया के बाइनरी फ़ाइल पर इंगित किया जाएगा। इसके मूल्य को पढ़ने के लिए readlink का उपयोग करें, फिर निष्पादन योग्य नाम काट दें और आपको निर्देशिका मिल जाएगी।

+1

क्या इस तरह की कार्यशील निर्देशिका की उपयोगकर्ता की पसंद को ओवरराइड करने के लिए यह अपरंपरागत नहीं है (या प्रोग्राम के रूप में 'chdir' का उपयोग करके मैंने उल्लेख किया है)? – gspr

+0

@gspr: बैश स्क्रिप्ट उपयोगकर्ता की कार्य निर्देशिका को ओवरराइड नहीं करता है। यह निष्पादन योग्य के लिए कार्य निर्देशिका को ओवरराइड करता है जो यह चलता है। क्योंकि इसकी जरूरत है। उपयोगकर्ता की निर्देशिका बदल नहीं रही है। –

+1

मेरा मतलब था कि इस कार्यक्रम के लिए उपयोगकर्ता की कामकाजी निर्देशिका * की पसंद *। इतनी बुरी आदत नहीं कर रही है? मेरा मतलब है, wilhelmtell के रूप में, Let_Me_Be और मैं सभी बताते हैं, वांछित लक्ष्य प्राप्त करने के बेहतर तरीके हैं। – gspr

1

वहाँ एक सवाल किया गया है कि कुछ समय पहले the location of the executable in C आप अपने config, संसाधन, आदि खोलने के लिए इस मार्ग का इस्तेमाल कर सकते लगाने के लिए कैसे ..

0

ठीक है, अपने कार्यक्रम के एक स्थान से एक फ़ाइल को खोलने के लिए की जरूरत है कि इस पर निर्भर करता है कि प्रोग्राम कहां स्थापित है, आपको शायद इसे संकलित-समय विकल्प बनाना चाहिए। क्या आपके बिल्ड सिस्टम ने कुछ सीपीपी मैक्रो को उस निर्देशिका को इंगित किया है जहां प्रश्न में डेटा फाइलें मिल सकती हैं। यह एक मानक "कॉन्फ़िगर, बनाने, स्थापित करने" में कॉन्फ़िगर करने के लिए --डेटादिर विकल्प है -बिल्ट प्रोग्राम अक्सर करता है।

बेशक, यदि आप वास्तव में चाहते हैं, तो आप chdir POSIX फ़ंक्शंस के साथ प्रोग्रामिंग डीआईआर को प्रोग्रामेटिक रूप से बदल सकते हैं। लेकिन जैसे मैंने कहा, यदि किसी प्रोग्राम को यह पता होना चाहिए कि यह कहां स्थित है, तो इसे संकलन-समय पर प्रदान किया जाना चाहिए। फिर आपको उपयोगकर्ता की कामकाजी डीआईआर की पसंद को ओवरराइड करने की आवश्यकता नहीं है। अपने कार्यक्रम (उदाहरण के ./programs/test/a.out के लिए) के सापेक्ष पथ है -

1

एक तरह से argv [0] का प्रयोग है। आप इस कार्यक्रम के नाम में कटौती करने और फाइल करने के लिए सापेक्ष पथ को जोड़ने, तो आप एक राक्षस (उदाहरण के ./programs/test/../../input_data के लिए) मिल जाएगा, लेकिन यह काम करना चाहिए।

+0

की बजाय शायद '$ @" में गुजरना चाहिए, यह गारंटी नहीं है, है ना? – ereOn

+0

यह माना जाता है कि वह कार्यक्रम को संशोधित कर सकता है। प्रश्न इस निर्देशिका में प्रोग्राम को निष्पादित करने के तरीके के बारे में है, प्रोग्राम को संशोधित करने और सापेक्ष पथ के साथ इस बग को ठीक करने के तरीके के बारे में नहीं है। –

+0

मैं argv कैसे भूल गया [0]? यह गलत हो सकता है क्योंकि यह 'execve' कॉल द्वारा सेट किया गया है, लेकिन यह आमतौर पर सही है और इसके लिए उपयोग करने के लिए पर्याप्त होना चाहिए। – nategoose

1

सबसे आसान तरीका करने के लिए हो सकता है या तो प्री-जाना जाता जगह (/ bin,/usr/bin, आदि) में अपने कार्यक्रम जाते थे। यदि नहीं, तो आप argv का उपयोग [0], कार्यक्रम का नाम (अंतिम भाग) को हटाने, और प्रयोग जो आपके कार्य निर्देशिका के रूप में सभी संबंधित पथ उपसर्ग (यदि आप जहां अपने कार्यक्रम है के सापेक्ष होने के लिए संबंधित पथ चाहते हैं) कर सकते हैं।

इसके अलावा, आप उपर्युक्त विधि का उपयोग करके अपने प्रोग्राम का पथ निर्धारित कर सकते हैं (argv[0] का उपयोग करें), और फिर इस निर्देशिका के साथ chdir() पर कॉल करें। तब से सभी सापेक्ष पथ कार्यक्रम के संबंध में होंगे।नोट, हालांकि, इस मामले में, आपको यह निर्धारित करना होगा कि argv[0] एक पूर्ण पथ रखता है या नहीं। यदि नहीं, तो आपको वर्तमान कामकाजी डीआईआर (getcwd()) प्राप्त करना होगा और फिर argv[0] के निर्देशिका भाग को जोड़ना होगा। नोट, हालांकि, वर्तमान काम dir बदल रहा है। आमतौर पर एक अच्छा विचार नहीं है, जैसे कि कोई उपयोगकर्ता आपको तर्क के रूप में फ़ाइल पथ देता है, यह आपके वर्तमान काम डीआईआर के सापेक्ष होगा, न कि प्रोग्राम कहां से संग्रहीत किया जाता है।

कुछ उदाहरण: कल्पना करें कि आपका प्रोग्राम /usr/bin में रहता है। अब

./bin/myprog 

, argv[0]: /usr में,

/usr/bin/myprog 

(कि argv[0] होगा निष्पादन योग्य नाम छँटाई और आप अपने dir है।।) या, जा रहा है कहते हैं,: आप अपने कार्यक्रम कॉल कर सकते हैं के रूप में एक सापेक्ष पथ है। आपको argv[0]: /usr/./bin/myprog में मौजूदा कामकाजी डीआईआर (/usr) को प्रीपेड करना होगा, और फिर निष्पादन योग्य नाम को फिर से शुरू करना होगा। निर्देशिका फिर से /usr/bin होगी।

0

सापेक्ष पथ का उपयोग न करें। पूर्ण पथ का प्रयोग करें। हो सकता है कि आप एक config.h हेडर फ़ाइल में निरंतर परिभाषित हो जाएं जो निर्दिष्ट करता है कि आपका निष्पादन योग्य कहां स्थापित है। फिर, उस स्ट्रिंग को अपने कोड में निर्दिष्ट किसी भी सापेक्ष पथ पर स्थिर करें।

+0

यह तब एक विशिष्ट स्थान पर स्थापित प्रोग्राम पर भरोसा करेगा और निर्देशिका स्थानांतरित होने पर कार्यक्षमता तोड़ देगा। – CJxD

2

openat एक विशेष निर्देशिका फ़ाइल डिस्क्रिप्टर से संबंधित एक फ़ाइल खोलता है जिसे आप पास करते हैं, लेकिन मुझे नहीं लगता कि वास्तव में आप वास्तव में क्या चाहते हैं (बिल्कुल)।

तो उस के लिए एक खुला कॉल रिश्तेदार (पथ, openat, या उस निर्देशिका के लिए वर्तमान निर्देशिका को बदलने का निर्माण करने के लिए या तो स्ट्रिंग ऑपरेटर्स का उपयोग) बनाते हैं तो आप निर्देशिका जहां मौजूदा निष्पादन योग्य है खोजने की जरूरत होगी, और।

निष्पादन योग्य खोजने के लिए आप readlink/proc/self/exe कर सकते हैं। readlink उस पथ को पढ़ता है जो एक प्रतीकात्मक लिंक इंगित करता है, और /proc/self/proc/<PID> पर एक प्रतीकात्मक लिंक है जहां <PID> वर्तमान प्रक्रिया की प्रक्रिया आईडी (कर्नेल में विशेष संभाल) है, और exe इसके तहत निष्पादन योग्य फ़ाइल का एक प्रतीकात्मक लिंक है उस प्रक्रिया के लिए। फिर आपको उस निष्पादन योग्य के रास्ते को बाहर निकालना होगा और इसका उपयोग करना होगा।

यह सब कहा जा रहा है, आपको आम तौर पर इस तरह से प्रोग्राम लिखने से बचना चाहिए कि वे अपनी निष्पादन योग्य फ़ाइल से संबंधित चीज़ों को ढूंढने की अपेक्षा करते हैं।

0

आप argv[0] पैरामीटर से निष्पादन पथ निर्धारित कर सकते हैं, लेकिन ऐसा करने पर सावधान रहें।

आपने जो वर्णन किया है वह एक प्रसिद्ध और अपेक्षित अर्थपूर्ण है। उपयोगकर्ता इस व्यवहार की उम्मीद करेंगे।

0

यहाँ कुछ कोड है कि आप अपने कार्यक्रम के भीतर से अपने को स्थापित-पथ को खोजने के लिए उपयोग कर सकते हैं (की जगह "test0002" अपने कार्यक्रम के नाम के साथ):

#include <iostream> 
#include <sstream> 
#include <string> 
#include <fstream> 
#include <unistd.h> 

///============================================================================= 
std::string FindInstallPath() 
{ 
    std::string sret=""; 
    int pid = (int)getpid(); 
    bool b=false; 
    std::string sf, s; 
    std::stringstream ss; 
    ss << "/proc/" << pid << "/maps"; 
    sf = ss.str(); 
    std::ifstream ifs(sf.c_str()); 
    size_t pos1, pos2; 
    while (!b && ifs.good()) 
    { 
     std::getline(ifs, s); 
     if ((pos1 = s.rfind("test0002")) != std::string::npos) 
     { 
      if ((pos2 = s.find_first_of('/')) != std::string::npos) 
      sret = s.substr(pos2, pos1 - pos2); 
      b = true; 
     } 
    } 
    if (!b) sret = ""; 
    ifs.close(); 
    return sret; 
} 
संबंधित मुद्दे