¿No se permite espacio en un nombre de archivo?

31

Se dice que en Unix y Linux en general, debe evitar tener espacios en un nombre de archivo de un archivo (archivo ordinario, directorio, enlace, archivo de dispositivo, ...).

Pero hago eso todo el tiempo. Para un nombre de archivo con un espacio adentro,

  • En Nautilus, el carácter de espacio se muestra como un espacio.
  • En la terminal Bash, utilizo \ para representar un espacio o encerrar el nombre del archivo dentro de un par de comillas dobles.
  • en los archivos de algunas aplicaciones (Nautilus, no estoy seguro si el sistema operativo también lo hará), el nombre del archivo se escribe con el espacio reemplazado por %20.

¿Realmente no se permite un espacio en un nombre de archivo?

¿Cómo utiliza o maneja un espacio en un nombre de archivo correctamente?

Tim
fuente
17
Está permitido pero es muy, muy molesto. No hay razón para ello. No lo hagas
Lightness compite con Monica el
3
También puede crear un archivo llamado -rf ~(uso touch -- "-rf ~"), pero no lo recomendaría.
Ian D. Scott, el
55
Puede hacerlo, está permitido, como crear un script de autodestrucción llamado "cd", pero no debe hacerlo. Su archivo ya se ve diferente en 3 herramientas diferentes, ¿no es lo suficientemente malo?
Falco
77
No todos comparten la opinión de que es realmente molesto. Y "No hay razón para ello" es tan obviamente falso que no necesita ser refutado. Me rendí y aprendí a manejar espacios correctamente hace años, y en su mayor parte no es gran cosa.
2
Los espacios @snailboat son un síntoma del problema real que es la falta de estandarización. Los sistemas de archivos Unix permiten "nombres" de archivos a blobs binarios casi sin restricciones. Los únicos bytes ilegales son 0 y 47 (el /separador). El uso de los 254 bytes restantes abre la puerta a todas las formas de "nombres" indescriptibles. Obviamente esto es una locura, pero no todos están de acuerdo en lo que es "cuerdo", y diferentes personajes romperán diferentes herramientas. La intersección de la cordura de todos es bastante pequeña .
jw013

Respuestas:

48

Los espacios, y de hecho todos los caracteres excepto /NUL, están permitidos en los nombres de archivo. La recomendación de no usar espacios en los nombres de archivo proviene del peligro de que puedan ser malinterpretados por un software que los admite de manera deficiente. Podría decirse que dicho software tiene errores. Pero también podría decirse que los lenguajes de programación como el scripting de shell hacen que sea muy fácil escribir software que se rompa cuando se presentan con nombres de archivo con espacios en ellos, y estos errores tienden a pasar porque los scripts de shell no suelen ser probados por sus desarrolladores usando nombres de archivos con espacios en ellos.

Los espacios reemplazados por %20no se ven a menudo en los nombres de archivo. Eso se usa principalmente para URL (web). Aunque es cierto que la codificación% de las URL a veces se abre paso en los nombres de archivo, a menudo por accidente.

Celada
fuente
66
Es "codificación URL" o "codificación porcentual" en.wikipedia.org/wiki/URL_encoding Según el nombre más apropiado es probablemente "codificación URI", pero a las personas les resulta más fácil decir url que URI , por lo que esta es una forma común de nombre equivocado. Observe que el conjunto de caracteres reservados en los URI es más grande que para los nombres de archivo * nix.
Ricitos de oro
1
@Tim No sé si puede especificar un carácter NUL en cualquier argumento de línea de comando en bash. Intenté algunas cosas como citarlo con Ctrl-V y algo así, $(echo -e \\0)pero no funcionó. El hecho es que la razón por la que NUL no se puede usar en los nombres de archivo es que no se puede usar en cadenas C (porque es el terminador de cadena) y todas las API subyacentes, así como prácticamente todas las cadenas manejadas por los programas C usan ese formato . Como bashestá escrito en C, es posible que simplemente no tenga ningún soporte para las cadenas con NUL en ellas. Podría estar equivocado, podría haber alguna forma oscura ...
Celada
1
Más o menos depende del contexto. Las funciones de cadena generalmente no cuentan el nulo final (o más bien, el primer nulo es el final de la cadena, incluso si hay cosas después), por lo que en ese sentido tiene una longitud cero y, por lo tanto, se consideraría vacío.
Ricitos de oro
3
@Celada, por supuesto, puedes usar NULy golpear, lo necesitas $'\0'. Por ejemplo:find . -print0 | while read -d $'\0' f; do echo "$f"; done
terdon
1
@goldilocks ¿Las personas en realidad pronuncian URL como 'url', rimando más o menos con 'earl'?
Miles Rout
17

Los espacios están permitidos en los nombres de archivo, como ha observado.

Si observa la entrada "la mayoría de los sistemas de archivos UNIX" en este cuadro en Wikipedia , notará:

  • Se permite cualquier conjunto de caracteres de 8 bits. También podemos incluir ASCII de 7 bits bajo este paraguas, ya que es un subconjunto de varios conjuntos de 8 bits y siempre se implementa utilizando bytes de 8 bits.

  • Los únicos caracteres prohibidos son /y "nulo". "Nulo" se refiere a un byte cero, pero de todos modos no están permitidos en los datos de texto.

Sin embargo , si utiliza el shell, puede darse cuenta de que hay algunos caracteres que crearán una molestia *, lo que es más significativo , que es un operador de POSIX globbing.

Dependiendo de cómo desee definir "molestia", puede incluir espacios en blanco (espacios, pestañas, líneas nuevas, etc.), ya que esto crea la necesidad de citar con "". Pero esto es inevitable, ya que los espacios están permitidos, así que ...

¿Cómo utiliza o maneja un espacio en un nombre de archivo correctamente?

En un contexto de línea de comando / shell, ajuste el nombre del archivo entre comillas simples o dobles (pero tenga en cuenta que no son los mismos problemas de WRT), o escape de los espacios con \, por ejemplo:

> foo my\ file\ with\ spaces\ in\ the\ name
encerrada dorada
fuente
1
¿Cómo se especifica el carácter NUL en bash? Quiero probarlo en un nombre de archivo.
Tim
1
No puedes La "semántica execve" se refiere al hecho de que en C (y en todos los demás lenguajes que conozco), las cadenas de texto están terminadas en nulo. La cáscara se implementa en C. Lo sneakest lo que podía pensar es touch $(echo -e "foo\00bar")- -eprocesos \0Ncomo un valor octal, pero todavía se pone en algún lugar perdido, como que sólo crea un archivo llamado foobar. Por supuesto, NULL no es imprimible, pero garantizo que desapareció debido a la restricción de la cadena C.
Ricitos de oro
"las cadenas de texto están terminadas en nulo" -> Para explicar más: las cadenas siempre se almacenan con un byte cero al final, por lo que "no está permitido" en el texto: si inserta una, ha terminado efectivamente la cadena en ese punto. Por ejemplo, foo[NULL]barterminaría como foopara la mayoría de los intentos y propósitos. El hecho de que eso no suceda con eso echo -emuestra que el NULL ha sido eliminado en alguna parte.
Ricitos de oro
55
La gran mayoría de los lenguajes de programación permiten caracteres nulos en cadenas. Simplemente sucede que el lenguaje principal que no es C, en el que se basa Unix, y la mayoría de los shells de Unix tampoco permiten caracteres nulos en las cadenas. En cualquier caso, @Tim, todas las interfaces de Unix usan cadenas terminadas en nulo, por lo que un byte nulo es lo único que nunca puede tener en un nombre de archivo (además de /que es el separador de directorio y no se puede citar, por lo que puede estar en un nombre de ruta pero no en un nombre de archivo).
Gilles 'SO- deja de ser malvado'
1
... pero [no importa otra vez]. No es algo que haría con demasiada frecuencia, de todos modos. En mi opinión, no hay razón para que estén en datos textuales. Hubiera corregido eso, pero es un comentario.
Ricitos de oro
3

La razón es en gran medida histórica: en el camino hacia atrás en la niebla de los espacios de tiempo no se permitían los nombres de archivo, por lo que los espacios se usaban como separadores de palabras clave / nombre de archivo. Los futuros intérpretes de shell tenían que ser inversamente compatibles con los scripts antiguos y, por lo tanto, estamos atrapados con el dolor de cabeza que tenemos hoy.

Los desarrolladores de procesos que no necesitan tratar mucho con los humanos pueden hacer las cosas mucho, mucho más fáciles al dejar espacios por completo. Apple hace esto, el contenido de / System / Library / CoreServices / contiene muy pocos espacios, los programas con espacios se abren en nombre del usuario yWouldLookStrangeIfCamelCased. Las rutas similares de solo Unix también evitan espacios.

(anécdota algo relacionada: a mediados de los 90, un dron de Windows dijo "Nombre una cosa que puede hacer en una Mac que no puedo hacer en Windows" -> "Use 12 caracteres en un nombre de archivo". -> Silencio. Los espacios fueron también posible en esos 12 caracteres)

Paul
fuente
1
Solía ​​usar V6 Unix (c. 1978). Se permitieron espacios entonces. Una tarea que tuve fue escribir un programa para analizar el sistema de archivos (usando E / S de disco directo) y buscar un archivo que tuviera espacios y espacios en blanco en su nombre.
wallyk
¿Caen espacios por completo o los nombres de archivo contienen muy pocos espacios?
mikeserv
2

Entonces, sí, como se dice muchas veces en otra parte, un nombre de archivo puede contener casi cualquier carácter. Pero hay que decir que un nombre de archivo no es un archivo. Tiene cierto peso como atributo de archivo, ya que normalmente necesita un nombre de archivo para abrir un archivo, pero el nombre de un archivo solo apunta al archivo real. Es un enlace, almacenado en el directorio que lo ha grabado, junto con el número de inodo , que es una aproximación mucho más cercana a un archivo real .

Entonces, ya sabes, llámalo como quieras. Al núcleo no le importa: todas las referencias de archivos que manejará tratarán con números de inodo reales de todos modos. El nombre de archivo es algo para consumo humano ; si quieres que sea una locura, bueno, es tu sistema de archivos. Aquí, haré algunas cosas locas:

Primero crearé 20 archivos y los nombraré con nada más que espacios, cada nombre de archivo contiene un espacio más que el anterior:

until [ $((i=$i+1)) -gt 20 ]
do  v=$v' ' && touch ./"$v"
done

Esto es un poco gracioso. Mira mi ls:

ls -d ./*
./      ./          ./              ./                  ./                 
./      ./          ./              ./                  ./                  
./      ./          ./              ./                  ./                   
./      ./          ./              ./                  ./     

Ahora voy a reflejar este directorio:

set -- * ; mkdir ../mirror
ls -i1qdU -- "$@" |
sh -c 'while read inum na
    do  ln -T "$1" ../mirror/$inum
    shift ; done' -- "$@"
ls -d ../mirror/*

Aquí están ../mirror/los contenidos:

../mirror/423759  ../mirror/423764  ../mirror/423769  ../mirror/423774
../mirror/423760  ../mirror/423765  ../mirror/423770  ../mirror/423775
../mirror/423761  ../mirror/423766  ../mirror/423771  ../mirror/423776
../mirror/423762  ../mirror/423767  ../mirror/423772  ../mirror/423777
../mirror/423763  ../mirror/423768  ../mirror/423773  ../mirror/423778

Ok, pero tal vez estás preguntando, pero ¿de qué sirve eso? ¿Cómo puedes saber cuál es cuál? ¿Cómo puede estar seguro de haber vinculado el número de inodo correcto al nombre de archivo correcto?

Bien...

echo "heyhey" >>./'    ' 
tgt=$(ls -id ./'    ')
cat ../mirror/${tgt%% .*} \
    $(ls -1td ../mirror/* | head -n1) 

SALIDA

heyhey
heyhey

Vea, tanto el número de inodo contenido ../mirror/"${tgt%% .*}"como el referenciado se ./' 'refieren al mismo archivo. Describen el mismo archivo. Lo nombran, pero nada más. No hay ningún misterio, en realidad, solo algunos inconvenientes que podrías hacerte, pero que finalmente tendrán poco o ningún efecto en el funcionamiento de tu sistema de archivos Unix al final.

mikeserv
fuente