c++ - usa - rutas de archivos en linux
¿Cómo abrir un archivo con su ruta relativa en Linux? (9)
Aquí hay un código que puede usar para encontrar su ruta de instalación desde su programa (reemplace "test0002" con el nombre de su programa):
#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;
}
Tengo un programa que abre un archivo usando una ruta relativa (por ejemplo ''..'').
Ahora el problema es que cuando ejecuto el programa desde otro directorio, la ruta relativa no es relativa al programa sino relativa al directorio de trabajo. Por lo tanto, si comienzo el programa con ''/ path / to / program / myprog'' no puede encontrar el archivo.
¿Hay alguna manera de ejecutar el programa independientemente del directorio de trabajo? Id est, as Si el directorio de trabajo era el directorio donde se encuentra el programa? ¿O simplemente estoy pensando de una manera demasiado complicada y hay una manera mucho más fácil de referirse a un archivo, cuya ubicación solo se conoce por su ruta relativa a la ruta del archivo de programa?
Bueno, si su programa necesita abrir un archivo desde una ubicación que depende de dónde está instalado el programa, probablemente debería hacer de esto una opción en tiempo de compilación. Haga que su sistema de compilación establezca una macro de CPP que indique el directorio donde se encuentran los archivos de datos en cuestión. Esto es lo que suele hacer la opción --datadir de configurar en un programa estándar "configurar, crear, hacer instalar".
Por supuesto, si realmente lo desea, puede cambiar programáticamente el directorio de trabajo con las funciones de chdir
POSIX. Pero como dije, si un programa necesita saber dónde está ubicado, esto debe proporcionarse en tiempo de compilación. Entonces no necesita anular la elección del directorio de trabajo del usuario.
La manera más fácil sería poner su programa en un lugar conocido (/ bin, / usr / bin, etc.). De lo contrario, puede usar el argv [0], eliminar el nombre del programa (la última parte) y usarlo como su directorio de trabajo para prefijar todas las rutas relativas (si desea que las rutas relativas sean relativas a su programa).
Además, puede determinar la ruta de su programa usando el método anterior (use argv[0]
), y luego llame a un chdir()
con este directorio. Todos los caminos relativos a partir de entonces serían relativos a donde está el programa. Tenga en cuenta, sin embargo, que en este caso, debe determinar si argv[0]
contiene una ruta absoluta. De lo contrario, debe obtener el directorio de trabajo actual ( getcwd()
) y anexar la parte de directorio de argv[0]
. Tenga en cuenta, sin embargo, que cambiar el directorio de trabajo actual. no es una buena idea, generalmente, como si un usuario le diera una ruta de archivo como argumento, será relativa a su directorio de trabajo actual, no relativo al lugar donde está almacenado el programa.
Algunos ejemplos: imagine que su programa vive en /usr/bin
. Puede llamar a su programa como:
/usr/bin/myprog
( argv[0]
sería argv[0]
. Pode el nombre del ejecutable y usted tiene su dir.) O, por ejemplo, en /usr
:
./bin/myprog
Ahora, argv[0]
es una ruta relativa. /usr/./bin/myprog
directorio de trabajo actual ( /usr
) al que está en argv[0]
: /usr/./bin/myprog
, y luego volver a podar el nombre del ejecutable. El directorio sería nuevamente /usr/bin
.
No use rutas relativas. Usa caminos absolutos. Es posible que tenga una constante definida en un archivo de encabezado config.h que especifique dónde está instalado su ejecutable. Luego, anteponga esa constante de cadena a cualquier ruta relativa que especifique en su código.
Puede determinar la ruta de ejecución desde el parámetro argv[0]
, pero tenga cuidado al hacerlo.
Lo que describes es una semántica bien conocida y esperada. Los usuarios esperarán este comportamiento.
Si el programa no lo está haciendo solo, es un mal programa. Los malos programas deben ser envueltos con un poco de scripts Bash:
#!/bin/bash
set -e
cd $(readlink -f $(dirname $0))
exec ./myprog $*
El script anterior determina el directorio donde está ubicado, luego cambia el directorio de trabajo actual a ese directorio y ejecuta un programa myprog
desde allí, pasando todos los parámetros de forma transparente. Por lo tanto, debe colocar esta secuencia de comandos en el mismo directorio donde se encuentra su programa y ejecutarlo en lugar de su programa.
Suponiendo que tiene acceso al código fuente y puede arreglar el programa, use proc fs para determinar la ubicación del programa y luego use la ruta absoluta.
Por ejemplo, /proc/self/exe
siempre será un enlace simbólico que apunta al archivo binario del proceso actual. Usa readlink
para leer su valor, luego corta el nombre del ejecutable y obtienes el directorio.
Una forma es usar argv [0]: hay una ruta relativa de su programa (por ejemplo, ./programs/test/a.out
). Si corta el nombre del programa y agrega la ruta relativa al archivo, obtendrá un monstruo (por ejemplo, ./programs/test/../../input_data
) pero debería funcionar.
openat
abre un archivo relativo a un descriptor de archivo de directorio en particular, lo pasas, pero no creo que eso sea realmente lo que quieres (exactamente).
Necesitará encontrar el directorio donde está el ejecutable actual y luego crear una llamada abierta relativa a eso (usando cualquiera de los operadores de cadena para construir la ruta, openat
o cambiar el directorio actual a ese directorio).
Para encontrar el ejecutable puede readlink
/proc/self/exe
. readlink
lee la ruta a la que apunta un enlace simbólico, y /proc/self
es un enlace simbólico a /proc/<PID>
donde <PID>
es el ID del proceso actual (manejado especial en el kernel), y el exe
debajo de eso hay un enlace simbólico al archivo ejecutable para ese proceso. Entonces necesitarás pescar la ruta a ese ejecutable y usar eso.
Dicho todo esto, generalmente debe evitar escribir programas de tal manera que esperen encontrar cosas relativas a su archivo ejecutable.
Hace algún tiempo, surgió la pregunta de cómo encontrar la ubicación del archivo ejecutable en C , podría usar esta ruta para abrir su configuración, recurso, etc.