Ejecutas un comando desde Git Bash que funciona sin problemas en otra terminal y el programa recibe algo distinto de lo que escribiste. Estos son los síntomas más habituales:
$ cmd /c script.bat
Microsoft Windows [Versión 10.0.xxxxx]
(c) Microsoft Corporation. Todos los derechos reservados.
C:\proyectos\mi-app>
$ ssh -i /home/usuario/.ssh/id_ed25519 mi-servidor
Warning: Identity file C:/Program Files/Git/home/usuario/.ssh/id_ed25519 not accessible: No such file or directory.
$ node leer.js G:\Mi unidad\datos\informe.txt
Error: ENOENT: no such file or directory, open 'G:Mi'
$ cd D:\proyectos\mi-app
bash: cd: D:proyectosmi-app: No such file or directory
También ocurre al pasar una ruta de Linux a docker exec o a wsl.exe: el programa recibe una ruta de Windows que no existe donde debería. Hay tres mecanismos distintos detrás, y cada uno tiene su arreglo.
Por qué pasa
1. Conversión automática de rutas. Git Bash se basa en MSYS2. La documentación de MSYS2 explica que, cuando se llama a un ejecutable nativo de Windows, los argumentos que parecen rutas Unix se convierten automáticamente a rutas de Windows, algo que según la propia documentación no es perfecto. Las notas de versión de Git for Windows describen el caso de las opciones que empiezan por una barra: /usr/bin/bash.exe se convierte en C:\Program Files\Git\usr\bin\bash.exe. La raíz / de MSYS corresponde a la carpeta de instalación de Git, y de ahí sale C:/Program Files/Git/.... Lo que recibe un programa nativo en una instalación de prueba:
/home/usuario/.ssh/id_ed25519 -> C:/Program Files/Git/home/usuario/.ssh/id_ed25519
--dir=/foo -> --dir=C:/Program Files/Git/foo
-L/regex/ -> -LC:/Program Files/Git/regex/
/c -> C:/
La última línea explica el primer síntoma: cmd.exe ya no recibe /c, así que abre una sesión interactiva y no ejecuta el script. La conversión no ocurre en PowerShell ni en cmd: es una función de MSYS2 al lanzar programas nativos desde Bash.
2. La barra invertida es el carácter de escape de Bash. Fuera de comillas, Bash elimina la barra y conserva el carácter siguiente, de modo que D:\proyectos\mi-app llega como D:proyectosmi-app. Además, un espacio sin comillas divide el argumento en dos, como en G:\Mi unidad.
3. Las rutas /tmp, /home o /usr solo existen dentro de MSYS. Un programa nativo que recibe la cadena literal /tmp/archivo la interpreta como una ruta desde la raíz de la unidad actual. Por eso un archivo creado en /tmp desde Bash puede no encontrarse desde un Python o un Node nativos. Dependiendo de la versión y de la configuración de Git for Windows, /tmp puede apuntar a la carpeta temporal del usuario o a una subcarpeta de la instalación de Git; compruébalo con cygpath -w /tmp.
Solución
-
Desactiva la conversión para un comando con
MSYS_NO_PATHCONV=1, que es lo que indican las notas de versión de Git for Windows:MSYS_NO_PATHCONV=1 docker exec mi-contenedor pg_restore -U postgres -d mi_db /var/backups/respaldo.dumpLa ruta llega intacta al contenedor. Si prefieres desactivarla en toda la sesión, usa
export MSYS_NO_PATHCONV=1, pero entonces tendrás que pasar tú mismo rutas válidas para Windows a los programas nativos. -
Excluye solo ciertos argumentos con
MSYS2_ARG_CONV_EXCL. Según la documentación de MSYS2, acepta*para excluirlos todos o una lista de prefijos separados por;:MSYS2_ARG_CONV_EXCL='/var;/home' docker exec mi-contenedor ls /var/backupsPara las variables de entorno existe
MSYS2_ENV_CONV_EXCL, que funciona de forma equivalente. -
Duplica la primera barra en las opciones. Las notas de versión de Git for Windows lo proponen como alternativa:
cmd //c script.bat taskkill //F //PID 1234El programa recibe
/c,/Fy/PIDsin convertir. Ten en cuenta que una ruta completa como//tmp/archivotiene forma de ruta UNC y puede llegar al programa con las dos barras, sin convertir; para rutas completas es más fiableMSYS_NO_PATHCONV=1. -
Escribe las rutas de Windows con barras normales o entre comillas simples. Windows acepta
/como separador, y las comillas simples impiden que Bash interprete la barra invertida:cd D:/proyectos/mi-app node leer.js 'G:\Mi unidad\datos\informe.txt' -
Convierte tú mismo con
cygpath. La documentación de Cygwin indica que-wimprime la forma de Windows con barras invertidas y-mla misma ruta con barras normales, útil en scripts de shell:node leer.js "$(cygpath -m /tmp/datos.json)" ssh -i ~/.ssh/id_ed25519 mi-servidorEn el caso de SSH, usa
~en lugar de/home/usuario: la tilde se expande a la carpeta de usuario de Windows y el cliente nativo encuentra la clave. -
Para WSL, ejecuta el comando de Linux dentro de
wsl.exe. La documentación de Microsoft indica que los comandos pasados awsl.exese reenvían sin modificar y que las rutas deben escribirse en formato WSL. Entre comillas simples, Git Bash no ve la ruta como argumento propio y no la toca:wsl.exe -e bash -lc 'ls /tmp && echo $HOME'Las comillas simples evitan que Git Bash expanda
$HOMEantes de enviar el comando.
Cómo verificar que quedó resuelto
Cualquier programa nativo que imprima sus argumentos sirve de prueba. Con Python:
python -c "import sys; print(sys.argv[1:])" /var/backups/respaldo.dump
MSYS_NO_PATHCONV=1 python -c "import sys; print(sys.argv[1:])" /var/backups/respaldo.dump
El primer comando muestra una ruta bajo C:/Program Files/Git/...; el segundo debe imprimir ['/var/backups/respaldo.dump']. Para cmd, comprueba que cmd //c echo hola imprime hola en lugar de abrir una sesión interactiva. Después repite el comando original (por ejemplo, la restauración con pg_restore dentro del contenedor) y confirma que termina sin errores de ruta.
Variantes y errores relacionados
Montar una carpeta con docker run -v
Un argumento como "$PWD":/datos contiene dos rutas separadas por dos puntos, y MSYS lo convierte en una lista separada por punto y coma (C:\...;C:\Program Files\Git\datos), que Docker no entiende. Pasa una ruta de Windows con barras normales en la parte del equipo anfitrión, que cygpath -m genera, y comprueba qué formato admite tu versión de Docker:
MSYS_NO_PATHCONV=1 docker run --rm -v "$(cygpath -m "$PWD")":/datos mi-imagen ls /datos
Se antepone MSYS_NO_PATHCONV=1 porque el argumento final, /datos, también empieza por una barra y docker.exe lo recibiría convertido.
docker cp no se ve afectado
En docker cp ./respaldo.dump mi-contenedor:/var/backups/ ningún argumento empieza por una barra, así que no se convierte nada. Si el destino empieza por /, aplican los pasos anteriores.
Archivos que Bash crea en /tmp y un programa nativo no encuentra
Pasa a la herramienta la ruta de Windows que devuelve cygpath -m, o crea los archivos de intercambio en una carpeta con ruta de Windows conocida.
Conviene saber qué se convierte
La conversión solo afecta a los argumentos (y variables de entorno) de programas nativos. Los comandos internos de Bash y los programas de MSYS, como ls, reciben las rutas tal cual.
Resumen
- MSYS2 convierte los argumentos que parecen rutas Unix al llamar a programas nativos de Windows; por eso aparecen rutas como
C:/Program Files/Git/...ycmd /cabre una sesión interactiva. - Bash trata la barra invertida como carácter de escape: usa barras normales o comillas simples en las rutas de Windows.
- Desactiva la conversión con
MSYS_NO_PATHCONV=1en el comando, o limítala conMSYS2_ARG_CONV_EXCL. - Para las opciones, duplica la barra:
cmd //c. Para pasar rutas reales de Windows, usacygpath -m. - Los comandos de Linux van dentro de
wsl.exe -e bash -lc '...'.
Comentarios
Publicar un comentario