如何在Linux中使用相对路径打开文件?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3988002/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 23:45:14  来源:igfitidea点击:

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

c++clinuxpath

提问by Burkhard

I have a program which opens a file by using a relative path (for instance '..').

我有一个程序,它使用相对路径(例如“..”)打开文件。

Now the problem is, when I execute the program from another directory, the relative path is not relative to the program but relative to the working directory. Thus, if I start the program with '/path/to/program/myprog' it fails to find the file.

现在的问题是,当我从另一个目录执行程序时,相对路径不是相对于程序而是相对于工作目录。因此,如果我使用 '/path/to/program/myprog' 启动程序,它将无法找到该文件。

Is there a way to execute the program independently of the working directory? Id est, as If the working directory were the directory where the program is located? Or am I just thinking in a too complicated way and there is a much easier way to refer to a file, which location is only known by its path relative to the path of the program file?

有没有办法独立于工作目录执行程序?Id est, as 如果工作目录是程序所在的目录?或者我只是想得太复杂了,有一种更简单的方法来引用文件,哪个位置只能通过相对于程序文件路径的路径知道?

采纳答案by Burkhard

If program is not doing it by itself, it is a bad program. Bad programs should be wrapped with a bit of Bash scripting:

如果程序不是自己做的,那就是一个坏程序。坏程序应该用一些 Bash 脚本来包装:

#!/bin/bash

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

The script above determines the directory where it is located, then changes current working directory to that directory and runs a program myprogfrom there, passing all parameters transparently. Thus, you have to put this script into the same directory where your program is located and run it instead of your program.

上面的脚本确定它所在的目录,然后将当前工作目录更改为该目录并myprog从那里运行程序,透明地传递所有参数。因此,您必须将此脚本放在您的程序所在的同一目录中并运行它而不是您的程序。

Assuming that you have the access to the source code and can fix the program, then use proc fsto determine the program's location and then use absolute path.

假设您可以访问源代码并且可以修复程序,然后使用proc fs确定程序的位置,然后使用绝对路径。

For example, /proc/self/exewill always be a symlink pointing at the binary file of the current process. Use readlinkto read its value, then cut executable name and you got the directory.

例如,/proc/self/exe将始终是指向当前进程的二进制文件的符号链接。使用readlink读取它的值,然后剪切可执行文件名,你就得到了目录。

回答by Nikolaus Gradwohl

there has been a question a while ago how to find the location of the executable in Cyou could use this path to open your config, resource, etc ..

前段时间有一个问题,如何在 C 中找到可执行文件的位置,您可以使用此路径打开您的配置、资源等。

回答by gspr

Well, if your program needs to open a file from a location that depends on where the program is installed, you should probably make this a compile-time option. Have your build system set some CPP macro indicating the directory where the data files in question can be found. This is what the --datadir option to configure in a standard "configure, make, make install"-built program often does.

好吧,如果您的程序需要从取决于程序安装位置的位置打开文件,您可能应该将其设为编译时选项。让您的构建系统设置一些 CPP 宏,指示可以找到相关数据文件的目录。这是在标准的“配置、制作、制作安装”程序中配置的 --datadir 选项经常做的事情。

Of course, if you really want to, you can programmatically change the working dir with the chdirPOSIX functions. But like I said, if a program needs to know where it is located, this should be provided at compile-time. Then you don't need to override the user's choice of working dir.

当然,如果您真的想要,您可以使用chdirPOSIX 函数以编程方式更改工作目录。但就像我说的,如果程序需要知道它的位置,这应该在编译时提供。然后您不需要覆盖用户对工作目录的选择。

回答by Adam Trhon

One way is to use argv[0] - there is relative path of your program (for example ./programs/test/a.out). If you cut the program name and add the relative path to file, you will get a monster (for example ./programs/test/../../input_data) but it should work.

一种方法是使用 argv[0] - 你的程序有相对路径(例如./programs/test/a.out)。如果您删除程序名称并添加文件的相对路径,您将得到一个怪物(例如./programs/test/../../input_data),但它应该可以工作。

回答by Diego Sevilla

The easiest way would be to either put your program in a pre-known place (/bin, /usr/bin, etc.). If not, you can use the argv[0], remove the program name (the last part), and use that as your working directory to prefix all relative paths (if you want relative paths to be relative to where your program is).

最简单的方法是将您的程序放在预先知道的位置(/bin、/usr/bin 等)。如果没有,您可以使用 argv[0],删除程序名称(最后一部分),并将其用作您的工作目录来为所有相对路径添加前缀(如果您希望相对路径相对于您的程序所在的位置)。

Also, you can determine the path of your program using the method above (use argv[0]), and then call a chdir()with this directory. All relative paths from then on would be relative to where the program is. Note, however, that in this case, you have to determine if argv[0]holds an absolute path. If not, you have to get the current working dir (getcwd()) and then append the directory part of argv[0]. Note, however, that changing the current work dir. is not a good idea, usually, as if a user gives you a file path as an argument, it will be relative to your current work dir, not relative to where the program is stored.

此外,您可以使用上述方法(使用argv[0])确定程序的路径,然后chdir()使用此目录调用 a 。从那时起所有的相对路径都将相对于程序所在的位置。但是请注意,在这种情况下,您必须确定是否argv[0]包含绝对路径。如果没有,则必须获取当前工作目录 ( getcwd()),然后附加argv[0]. 但是请注意,更改当前工作目录。不是一个好主意,通常,如果用户给你一个文件路径作为参数,它将相对于你当前的工作目录,而不是相对于程序的存储位置。

Some examples: Imagine your program lives in /usr/bin. You can call your program as:

一些例子: 想象一下你的程序存在于/usr/bin. 您可以将您的程序称为:

./bin/myprog

(that would be argv[0]. Prune the executable name and you have your dir.) Or, being, say, in /usr:

(那就是argv[0]. 修剪可执行文件名,你就有了你的目录。)或者,比如说,在/usr

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

Now, argv[0]is a relative path. You have to prepend current working dir (/usr) to the one in the argv[0]: /usr/./bin/myprog, and then again prune the executable name. The directory would be again /usr/bin.

现在,argv[0]是一个相对路径。您必须将当前工作目录 ( /usr) 放在argv[0]: 中的目录之前/usr/./bin/myprog,然后再次修剪可执行文件名称。该目录将再次出现/usr/bin

回答by wilhelmtell

Don't use relative paths. Use absolute paths. You might have a constant defined in a config.h header file that specifies where your executable is installed. Then, prepend that string constant to any relative path you specify in your code.

不要使用相对路径。使用绝对路径。您可能在 config.h 头文件中定义了一个常量,用于指定可执行文件的安装位置。然后,将该字符串常量添加到您在代码中指定的任何相对路径。

回答by nategoose

openatopens a file relative to a particular directory file descriptor you pass it, but I don't think that is really what you want (exactly).

openat打开一个与您传递的特定目录文件描述符相关的文件,但我认为这不是您真正想要的(正是)。

You will need to find the directory where the current executable is, and then create an open call relative to that (using either string operators to build the path, openat, or changing the current directory to that directory).

您需要找到当前可执行文件所在的目录,然后创建一个相对于该目录的打开调用(使用字符串运算符构建路径openat,或将当前目录更改为该目录)。

To find the executable you can readlink/proc/self/exe. readlinkreads the path that a symbolic link points to, and /proc/selfis a symbolic link to /proc/<PID>where <PID>is the process ID of the current process (handled special in the kernel), and the exeunder that is a symbolic link to the executable file for that process. Then you'll need to fish out the path to that executable and use that.

要查找可执行文件,您可以readlink/proc/self/exe. readlink读取路径的符号链接指向,并且/proc/self是一个符号链接到/proc/<PID>其中<PID>是当前进程(在内核处理特殊)的进程ID,并且exe根据该是一个符号链接到该进程的可执行文件。然后您需要找出该可执行文件的路径并使用它。

All of that being said, you usually should avoid writing programs in such a way that they expect to find things relative to their executable file.

尽管如此,您通常应该避免以这样一种方式编写程序,即他们期望找到与其可执行文件相关的内容。

回答by ?imon Tóth

You can determine the execution path from the argv[0]parameter, but be careful when doing so.

您可以根据argv[0]参数确定执行路径,但这样做时要小心。

What you described is a well known and expected semantic. Users will expect this behaviour.

你所描述的是一个众所周知的和预期的语义。用户会期望这种行为。

回答by slashmais

Here is some code you can use to find your install-path from within your program (replace "test0002" with the name of your program):

下面是一些代码,你可以用来在你的程序中找到你的安装路径(用你的程序名称替换“test0002”):

##代码##