Как открыть файл с его относительным путем в Linux? - PullRequest
7 голосов
/ 21 октября 2010

У меня есть программа, которая открывает файл, используя относительный путь (например, '..').

Теперь проблема в том, что когда я запускаю программу из другого каталога, относительный путь не относительно программы, а относительно рабочего каталога. Таким образом, если я запускаю программу с «/ path / to / program / myprog», она не может найти файл.

Есть ли способ выполнить программу независимо от рабочего каталога? То есть, как если бы рабочий каталог был каталогом, в котором находится программа? Или я просто слишком сложным образом думаю, и существует гораздо более простой способ обратиться к файлу, местоположение которого известно только по его пути относительно пути к файлу программы?

Ответы [ 9 ]

4 голосов
/ 21 октября 2010

Если программа не делает это сама по себе, это плохая программа.Плохие программы должны быть обернуты небольшим количеством сценариев Bash:

#!/bin/bash

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

Приведенный выше скрипт определяет каталог, в котором он находится, затем меняет текущий рабочий каталог на этот каталог и запускает программу myprog оттудапередача всех параметров прозрачно.Таким образом, вы должны поместить этот скрипт в тот же каталог, где находится ваша программа, и запустить его вместо вашей программы.

Предполагая, что у вас есть доступ к исходному коду и вы можете исправить программу, используйте proc fs для определения местоположения программы и последующего использования абсолютного пути.

Например, /proc/self/exe всегда будет символической ссылкой, указывающей на двоичный файл текущего процесса.Используйте readlink, чтобы прочитать его значение, затем вырежьте имя исполняемого файла, и вы получите каталог.

2 голосов
/ 21 октября 2010

openat открывает файл относительно определенного дескриптора файла каталога, который вы передаете, но я не думаю, что это именно то, что вам нужно (именно).

Вам нужно будет найти каталог, гдетекущим исполняемым файлом является, а затем создайте открытый вызов относительно этого (используя строковые операторы для построения пути, openat или изменив текущий каталог на этот каталог).

Чтобы найти исполняемый файл, вы можетеreadlink /proc/self/exe.readlink читает путь, на который указывает символическая ссылка, а /proc/self является символической ссылкой на /proc/<PID>, где <PID> - это идентификатор текущего процесса (обрабатывается специальным образом в ядре), а exeпод ним находится символическая ссылка на исполняемый файл для этого процесса.Затем вам нужно будет найти путь к этому исполняемому файлу и использовать его.

При этом, как правило, следует избегать написания программ таким образом, чтобы они ожидали найти что-то относительно своего исполняемого файла..

1 голос
/ 21 октября 2010

Самый простой способ - это поместить вашу программу в заранее известное место (/ 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] - это относительный путь.Вам необходимо добавить текущий рабочий каталог (/usr) к одному из argv[0]: /usr/./bin/myprog, а затем снова удалить имя исполняемого файла.Каталог будет снова /usr/bin.

1 голос
/ 21 октября 2010

Один из способов - использовать argv [0] - есть относительный путь вашей программы (например, ./programs/test/a.out). Если вы урежете имя программы и добавите относительный путь к файлу, вы получите монстра (например, ./programs/test/../../input_data), но он должен работать.

1 голос
/ 21 октября 2010

недавно был вопрос, как найти расположение исполняемого файла в C Вы можете использовать этот путь, чтобы открыть свой конфиг, ресурс и т.д ..

0 голосов
/ 21 октября 2010

Вот код, который вы можете использовать, чтобы найти путь установки из вашей программы (замените «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;
}
0 голосов
/ 21 октября 2010

Вы можете определить путь выполнения из параметра argv[0], но будьте осторожны при этом.

То, что вы описали, является хорошо известной и ожидаемой семантикой.Пользователи ожидают такого поведения.

0 голосов
/ 21 октября 2010

Не используйте относительные пути.Используйте абсолютные пути.В заголовочном файле config.h может быть определена константа, которая указывает, где установлен ваш исполняемый файл.Затем добавьте эту строковую константу к любому относительному пути, который вы указали в своем коде.

0 голосов
/ 21 октября 2010

Что ж, если вашей программе нужно открыть файл из местоположения, которое зависит от того, где установлена ​​программа, вы, вероятно, должны сделать это параметром времени компиляции. Сделайте так, чтобы ваша система сборки установила некоторый макрос CPP, указывающий каталог, в котором можно найти рассматриваемые файлы данных. Это то, что часто можно сделать с помощью параметра --datadir в стандартной программе «configure, make, make install».

Конечно, если вы действительно хотите, вы можете программно изменить рабочий каталог с помощью функций chdir POSIX. Но, как я уже сказал, если программе нужно знать, где она находится, это должно быть предоставлено во время компиляции. Тогда вам не нужно отменять выбор пользователем рабочего каталога.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...