¿Cómo maneja Linux múltiples separadores de ruta consecutivos (/ home //// nombre de usuario /// archivo)?

111

Estoy trabajando en un script de Python que pasa las ubicaciones de los archivos a un subproceso scp. Todo está bien, pero estoy en una situación en la que puedo terminar concatenando una ruta con un nombre de archivo de modo que haya un doble ' /en la ruta. Sé que a bash no le importa si tienes varios separadores de archivos, pero me pregunto cómo se rectifica exactamente eso. ¿Es bash lo que te quita más /o realmente no importa nunca?

Pregunto porque me ahorrará varias líneas de código para verificar si hay /s adicionales mientras concatena. Sé que no es gran cosa, pero también tengo curiosidad. Tengo un script bash que tiene la línea cd //usr(en lugar de cd /usr), lo que parece implicar que podría ser importante usar múltiples /s en una ruta

Falmarri
fuente
77
Invertiría en las líneas adicionales de código ...
Stefan
55
Por si acaso a alguien le interesa, que estoy seguro que nadie lo hace, lo hice en realidad estar usando la pitón joiny abspathy tales órdenes.
Falmarri

Respuestas:

165

Se permiten múltiples barras y son equivalentes a una sola barra. De la especificación Single Unix (versión 3) , definiciones básicas §3.266 nombre de ruta : "Varias barras sucesivas se consideran lo mismo que una barra".

Hay una excepción: si un nombre de ruta comienza con exactamente dos barras, puede tratarse de manera diferente (ref: definiciones básicas §4.11 resolución de nombre de ruta ). Linux en sí mismo no hace esto, aunque algunas aplicaciones podrían hacerlo, y otros sistemas unix-ish sí (por ejemplo, Cygwin).

Un final /al final de un nombre de ruta obliga al nombre de ruta a referirse a un directorio. En las definiciones de base ( POSIX 1003.1-2001 (Single Unix v3) §4.11 resolución de nombre de ruta , un final /es equivalente a un final /.. POSIX 1003.1-2008 (Single Unix v4) definiciones de base §4.12 elimina el requisito de hacerlo equivalente a /., en orden para hacer frente a directorios no existentes (p. ej., mkdir foo/se requiere que funcione, mientras mkdir foo/.que no lo haría; consulte la justificación del cambio).

Para los programas que actúan en una entrada de directorio, si fooes un enlace simbólico a un directorio, entonces pasar foo/es una forma de hacer que el programa actúe en el directorio en lugar del enlace simbólico.

¹ Tenga en cuenta que esto solo se aplica a la resolución del nombre de ruta, es decir, al acceder a los archivos. Las manipulaciones de nombre de archivo pueden funcionar de manera diferente. Por ejemplo, basenamee dirnameignore las barras diagonales finales.

Gilles
fuente
77
El equivalente a /.ha sido eliminado después de un proceso de discusión posterior, ya que era ambiguo. De todos modos, +1 ya que encontrar este tipo de información bien resumida es difícil.
hakre
17

El sistema operativo tampoco parece importarle, ya que acaba de probar un programa en C con una syscall directa para abrir con un // en la ruta.

Sin embargo, puede usar la función de biblioteca de python os.path.normpath para normalizarlo, lo que le ahorra tener que escanear a través de la cadena en busca de extras. Otros idiomas tienen funciones similares.

http://docs.python.org/library/os.path.html#os.path.normpath

Ivatar
fuente
55
Tenga cuidado con el siguiente comentario en la fuente de normpath: Normalice una ruta, por ejemplo, A // B, A /./ B y A / foo /../ B se convierten en A / B. ¡Debe entenderse que esto puede cambiar el significado de la ruta si contiene enlaces simbólicos!
Bluehorn
8

En todos los sistemas Unix que he visto, es lo mismo que un solo /, pero el estándar Unix especifica que

Un nombre de ruta que comience con dos barras sucesivas puede interpretarse de una manera definida por la implementación, aunque más de dos barras diagonales principales se tratarán como una sola barra diagonal.

por lo que puede manejarse especialmente, dependiendo de su sistema. (Algunas versiones anteriores de Unix usaban un doble encabezado /para el acceso remoto al sistema de archivos, y aún puede haber algunas que lo hagan).

Fred Foo
fuente
77
Cygwin (aunque no es un UNIX real) se traduce //remote/...en acceso remoto al sistema de archivos, probablemente por coherencia con Windows ' \\remote\....
Ephemient
2
Creo (pero no puedo buscar en Google una buena referencia en este momento) que las API de compatibilidad con POSIX de Windows también tratarán //remote/...lo mismo que el \\remote\...formato de ruta UNC .
Stephen P
1
Creo recordar que los nombres de ruta portátiles de Boost.Filesystem se manejan //de una manera especial, ya que pueden probar falseque son absolutos, conforme a la especificación Unix / POSIX.
7

Úselo os.path.joinen Python y no obtendrá múltiples barras. Construir nombres de archivo usted mismo concatenando cadenas se considera un estilo pobre de Python.

Neil Mayhew
fuente
Estoy de acuerdo, pero el nombre de archivo es parte de una cadena de comando, y en lugar de analizar la cadena de comando para agregar al nombre de archivo (al final), me gustaría agregarlo.
Falmarri
1
@Falmarri: ¡No puede simplemente agregar un nombre de archivo a una cadena de comando! El shell analizará una cadena de comando, por lo que se deben citar caracteres especiales en los nombres de archivo. Por lo tanto, debe construir el nombre del archivo, luego citarlo correctamente para ponerlo en la cadena de comando.
Gilles
Este es un proyecto realmente específico que solo voy a usar yo mismo. Probablemente no he sido lo suficientemente claro como para justificar no ser robusto sobre esto. Estoy obteniendo esta cadena de ruta de archivo de una clase que me da una ruta de archivo con escape correcto y tal. Y lo agrego a un argumento de línea de comando
Falmarri, el
1
@Falmarri: así que usa Normpath para limpiar el valor de la línea de comandos que no controlas, y luego usa join para unirlos.
Neil Mayhew
Esto es en realidad lo que terminé haciendo = \ No pude manejar el caso especial donde me dieron /muy bien.
Falmarri
3

No hay diferencia.

Se ignoran varias barras (sin efecto), por ejemplo:

ls -al //usr///////bin/sed
ChristopheD
fuente
77
No puede ser si es exactamente dos y al principio; Un nombre de ruta que comienza con dos barras sucesivas puede interpretarse de una manera definida por la implementación . En la práctica, creo que esto es correcto y simplemente son ignorados
Michael Mrozek
Gracias Chris, agradezco la aclaración! (desafortunadamente el inicio de sesión de OpenID no funciona para mí o lo votaría)
@Rob Usted no está registrado, pero aún está conectado (su cookie lo rastrea). Debería poder registrarse ahora para conectar un OpenID a su cuenta, pero debería poder votar de cualquier manera
Michael Mrozek
Gracias Michael pero "tienes que iniciar sesión o registrarte para votar". Cuando usa solo una dirección de correo electrónico y un nombre, no tiene todos los privilegios. Y dado que OpenID se está agotando y no tengo ganas de crear otra cuenta, no tengo suerte. Supongo que es mi culpa por ser flojo, pero agradezco la ayuda.
0

Por supuesto, puede normalizar una ruta con posibles múltiples / (barras) en ella al pasarla tr -s

NORMALIZED=$(echo "$UNHYGIENIC" | tr -s / /)

... y luego usar $NORMALIZED

Sin embargo, debería ser necesario. En cuanto a lo que sé, cualquier núcleo de UNIX correctamente debe ignorar los separadores de ruta concurrentes --- o conceptualmente tratarlos como ... /./...

Jim Dennis
fuente
"debería" -> "no debería".