簡體   English   中英

如何在Linux中使用它的相對路徑打開文件?

[英]How to open a file with it's relative path in Linux?

我有一個程序,通過使用相對路徑(例如'..')打開文件。

現在問題是,當我從另一個目錄執行程序時,相對路徑不是相對於程序而是相對於工作目錄。 因此,如果我使用'/ path / to / program / myprog'啟動程序,則無法找到該文件。

有沒有辦法獨立於工作目錄執行程序? Id est,as如果工作目錄是程序所在的目錄? 或者我只是以一種過於復雜的方式思考,並且有一種更簡單的方式來引用文件,哪個位置只能通過相對於程序文件路徑的路徑來識別?

如果程序本身沒有這樣做,那就是一個糟糕的程序。 糟糕的程序應該包含一些Bash腳本:

#!/bin/bash

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

上面的腳本確定它所在的目錄,然后將當前工作目錄更改為該目錄,並從那里運行程序myprog ,透明地傳遞所有參數。 因此,您必須將此腳本放在程序所在的同一目錄中並運行它而不是您的程序。

假設您可以訪問源代碼並可以修復程序,那么使用proc fs確定程序的位置,然后使用絕對路徑。

例如, /proc/self/exe將始終是指向當前進程的二進制文件的符號鏈接。 使用readlink讀取它的值,然后刪除可執行文件名,你就得到了目錄。

openat打開一個相對於你傳遞它的特定目錄文件描述符的文件,但我認為這不是你想要的(確切地說)。

您將需要找到當前可執行文件所在的目錄,然后創建相對於該目錄的打開調用(使用字符串運算符構建路徑, openat或將當前目錄更改為該目錄)。

要查找可執行文件,您可以readlink /proc/self/exe readlink讀取符號鏈接指向的路徑, /proc/self/proc/<PID>的符號鏈接,其中<PID>是當前進程的進程ID(在內核中特殊處理),以及exe在那下面是該進程的可執行文件的符號鏈接。 然后你需要刪除該可執行文件的路徑並使用它。

所有這一切,你通常應該避免編寫程序,他們希望找到相對於他們的可執行文件的東西。

前一段時間有一個問題如何在C中找到可執行文件的位置,您可以使用此路徑打開您的配置,資源等。

一種方法是使用argv [0] - 程序的相對路徑(例如./programs/test/a.out )。 如果你剪切程序名稱並添加文件的相對路徑,你將獲得一個怪物(例如./programs/test/../../input_data ),但它應該工作。

最簡單的方法是將程序放在預先知道的位置(/ bin,/ usr / bin等)。 如果沒有,您可以使用argv [0],刪除程序名稱(最后一部分),並將其用作工作目錄,以前綴所有相對路徑(如果您希望相對路徑相對於程序所在的位置)。

此外,您可以使用上述方法確定程序的路徑(使用argv[0] ),然后使用此目錄調用chdir() 從那時起,所有相對路徑都與程序所在的位置相關。 但請注意,在這種情況下,您必須確定argv[0]包含絕對路徑。 如果沒有,則必須獲取當前工作目錄( getcwd() ),然后附加argv[0]的目錄部分。 但請注意,更改當前工作目錄。 通常不是一個好主意,好像用戶給你一個文件路徑作為參數,它將相對於你當前的工作目錄,而不是相對於存儲程序的位置。

一些例子:想象一下你的程序存在於/usr/bin 您可以將您的計划稱為:

/usr/bin/myprog

(那將是argv[0] 。修剪可執行文件的名稱,你有你的目錄。)或者,比如說, /usr

./bin/myprog

現在, argv[0]是一個相對路徑。 您必須在argv[0]/usr /usr/./bin/myprog當前工作目錄( /usr ),然后再次修剪可執行文件名。 該目錄將再次是/usr/bin

好吧,如果您的程序需要從某個位置打開文件,該位置取決於程序的安裝位置,您應該將其作為編譯時選項。 讓您的構建系統設置一些CPP宏,指示可以找到相關數據文件的目錄。 這是在標准的“configure,make,make install”構建程序中經常配置的--datadir選項。

當然,如果您真的想要,可以使用chdir POSIX函數以編程方式更改工作目錄。 但就像我說的,如果一個程序需要知道它的位置,那么應該在編譯時提供。 然后,您不需要覆蓋用戶對工作目錄的選擇。

不要使用相對路徑。 使用絕對路徑。 您可能在config.h頭文件中定義了一個常量,指定可執行文件的安裝位置。 然后,將該字符串常量前置到您在代碼中指定的任何相對路徑。

您可以從argv[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;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM