O espaço não é permitido em um nome de arquivo?

31

Diz-se que no Unix e Linux em geral, você deve evitar espaços no nome do arquivo (arquivo comum, dir, link, arquivo do dispositivo, ...).

Mas eu faço isso o tempo todo. Para um nome de arquivo com um espaço dentro,

  • No Nautilus, o caractere de espaço é mostrado como um espaço.
  • No terminal Bash, eu uso \ para representar um espaço ou coloque o nome do arquivo dentro de um par de aspas duplas.
  • nos arquivos de alguns aplicativos (Nautilus, não tenho certeza se o SO também o fará), o nome do arquivo é gravado com o espaço substituído por %20.

Um espaço realmente não é permitido em um nome de arquivo?

Como você usa ou lida com um espaço em um nome de arquivo corretamente?

Tim
fonte
17
É permitido, mas é muito, muito chato. Não há razão para isso. Não faça isso.
Lightness Races com Monica
3
Você também pode criar um arquivo chamado -rf ~(use touch -- "-rf ~"), mas eu não o recomendaria.
31560 Ian
5
Você pode fazer isso, é permitido, como criar um script de autodestruição chamado "cd", mas não deve fazê-lo. Seu arquivo já parece diferente em três ferramentas diferentes, não é ruim o suficiente?
Falco
7
Nem todo mundo compartilha da opinião de que é realmente muito chato. E "não há razão para isso" é tão obviamente falso que não precisa ser refutado. Eu cedi e aprendi a lidar com espaços adequadamente anos atrás, e na maioria das vezes não é realmente um grande problema.
2
Os espaços do @snailboat são um sintoma do problema real, que é a falta de padronização. Os sistemas de arquivos Unix permitem que "nomes" de arquivo blobs binários quase irrestritos. Os únicos bytes ilegais são 0 e 47 (o /separador). O uso de todos os 254 bytes restantes abre a porta para todas as maneiras de "nomes" indescritíveis. Obviamente, isso é insano, mas nem todos concordam com o que é "sã", e personagens diferentes quebram ferramentas diferentes. A interseção da sanidade de todos é bem pequena .
jw013

Respostas:

48

Espaços, e de fato todos os caracteres, exceto /NUL, são permitidos nos nomes de arquivos. A recomendação de não usar espaços nos nomes de arquivos vem do perigo de que eles possam ser mal interpretados pelo software que os suporta mal. Indiscutivelmente, esse software é com erros. Mas também é possível argumentar que linguagens de programação como shell script facilitam a criação de softwares que quebram quando apresentados com nomes de arquivos com espaços neles, e esses bugs tendem a desaparecer porque os scripts de shell geralmente não são testados por seus desenvolvedores usando nomes de arquivos com espaços em eles.

Os espaços substituídos por %20geralmente não são vistos nos nomes de arquivos. Isso é usado principalmente para URLs (da web). Embora seja verdade que a codificação% de URLs às vezes entra em nomes de arquivos, geralmente por acidente.

Celada
fonte
6
É de "encoding URL" ou "codificação por cento" en.wikipedia.org/wiki/URL_encoding Como por que o nome mais adequado é, provavelmente, "encoding URI", mas as pessoas acham url mais fácil dizer do que URI , por isso esta é uma forma comum de nome impróprio. Observe que o conjunto de caracteres reservados nos URIs é maior que nos nomes de arquivos * nix.
precisa saber é o seguinte
11
@ Tim Não sei se você pode especificar um caractere NUL em qualquer argumento da linha de comando bash. Tentei algumas coisas, como citá-lo com Ctrl-V e algo assim, $(echo -e \\0)mas não funcionou. O motivo é que o NUL não pode ser usado nos nomes de arquivos é que ele não pode ser usado nas strings C (porque é o terminador de strings) e todas as APIs subjacentes e praticamente todas as strings manipuladas pelos programas C usam esse formato . Como bashestá escrito em C, ele pode simplesmente não ter suporte para nenhuma string com NUL. Eu posso estar errado, pode haver alguma maneira obscura ...
Celada
11
Meio que depende do contexto. As funções de string geralmente não contam o nulo final (ou melhor, o primeiro nulo é o fim da string, mesmo que exista alguma coisa a seguir); portanto, nesse sentido, ele tem comprimento zero e, portanto, seria considerado vazio.
Goldilocks
3
@ Celada é claro que você pode usar NULe bash, você precisa $'\0'. Por exemplo:find . -print0 | while read -d $'\0' f; do echo "$f"; done
terdon
11
@goldilocks As pessoas realmente pronunciam URL como 'url', rimando com 'earl'?
Route de milhas 8/08/08
17

Os espaços são permitidos nos nomes de arquivos, como você observou.

Se você olhar a entrada "a maioria dos sistemas de arquivos UNIX" neste gráfico na wikipedia , você notará:

  • Qualquer conjunto de caracteres de 8 bits é permitido. Também podemos incluir ASCII de 7 bits nesse guarda-chuva, pois é um subconjunto de vários conjuntos de 8 bits e é sempre implementado usando bytes de 8 bits.

  • Os únicos caracteres proibidos são / e "nulos". "Nulo" refere-se a um byte zero, mas eles não são permitidos nos dados de texto.

No entanto , se você fizer uso do shell, poderá perceber que existem alguns caracteres que criarão um incômodo, mais significativamente *, que é um operador de globos POSIX.

Dependendo de como você deseja definir "aborrecimento", você pode incluir espaços em branco (espaços, guias, novas linhas etc.), pois isso cria a necessidade de citar "". Mas isso é inevitável, pois os espaços são permitidos, então ...

Como você usa ou lida com um espaço em um nome de arquivo corretamente?

Em um contexto de shell / linha de comando, coloque o nome do arquivo entre aspas simples ou duplas (mas observe que eles não são os mesmos outros problemas do WRT) ou escape dos espaços com \, por exemplo:

> foo my\ file\ with\ spaces\ in\ the\ name
Cachinhos Dourados
fonte
11
Como você especifica caracteres NUL no bash? Eu quero testá-lo em um nome de arquivo.
Tim
11
Você não pode. A "semântica executiva" refere-se ao fato de que em C (e em todos os outros idiomas que conheço), as seqüências de texto são terminadas em nulo. O shell é implementado em C. A coisa mais rápida que eu conseguia pensar é touch $(echo -e "foo\00bar")- -eprocessos \0Ncomo um valor octal, mas ainda se perde em algum lugar, pois isso apenas cria um arquivo chamado foobar. É claro que NULL não pode ser impresso, mas eu garanto que ele foi embora por causa da restrição da string C.
Aprovado
"strings de texto são terminadas em nulo" -> Para explicar mais: strings são sempre armazenadas com um byte zero no final, e é por isso que "não é permitido" no texto: se você inserir um, você efetivamente encerrou a string nesse ponto. Por exemplo, foo[NULL]baracabaria como foopara a maioria das intenções e propósitos. O fato de que isso não acontece echo -emostra que o NULL foi removido em algum lugar.
goldilocks
5
A grande maioria das linguagens de programação permite caracteres nulos nas strings. Acontece que o idioma principal que não é o C, no qual o Unix é construído - e a maioria dos shells do Unix também não permite caracteres nulos nas strings. De qualquer forma, @Tim, todas as interfaces Unix usam cadeias terminadas em nulo; portanto, um byte nulo é a única coisa que você nunca pode ter em um nome de arquivo (além de /que é o separador de diretório e não pode ser citado, por isso pode estar em um nome de caminho mas não em um nome de arquivo).
Gilles 'SO- stop be evil'
11
... mas [não se preocupe novamente]. Não é algo que eu faria com muita frequência, de qualquer maneira. Na minha opinião, não há razão para eles estarem em dados textuais. Eu teria corrigido isso, mas é um comentário.
precisa saber é o seguinte
3

O motivo é amplamente histórico - WAY de volta à névoa de espaços de tempo não era permitido nos nomes de arquivos, portanto, os espaços eram usados ​​como separadores de palavra-chave / nome de arquivo. Os futuros intérpretes de shell precisavam ser compatíveis reversamente com scripts antigos e, portanto, estamos presos à dor de cabeça que temos hoje.

Os desenvolvedores de processos que não precisam lidar muito com seres humanos podem facilitar muito as coisas, eliminando completamente os espaços. A Apple faz isso, o conteúdo de / System / Library / CoreServices / contém muito poucos espaços, os programas com espaços são abertos em nome do usuário e oWouldLookStrangeIfCamelCased. Caminhos semelhantes apenas para unix também evitam espaços.

(anedota um pouco relacionada: em meados dos anos 90, um drone do Windows dizia "Cite uma coisa que você pode fazer em um Mac que não posso fazer no Windows" -> "Use 12 caracteres em um nome de arquivo." -> Silêncio. também é possível nesses 12 caracteres)

Paulo
fonte
11
Eu costumava usar o V6 Unix (c. 1978). Os espaços eram permitidos então. Uma tarefa que tive foi escrever um programa para analisar o sistema de arquivos (usando a E / S de disco direto) e procurar um arquivo que tivesse espaços e backspaces em seu nome.
wallyk
eles eliminam completamente os espaços - ou os nomes de arquivos contêm muito poucos espaços?
precisa saber é o seguinte
2

Então, sim, como afirmado várias vezes em outros lugares, um nome de arquivo pode conter praticamente qualquer caractere. Mas é preciso dizer que um nome de arquivo não é um arquivo. Ele tem algum peso como atributo de arquivo, na medida em que você normalmente precisa de um nome de arquivo para abrir um arquivo, mas o nome de um arquivo apenas aponta para o arquivo real. É um link, armazenado no diretório que o gravou, ao lado do número do inode - que é uma aproximação muito mais próxima de um arquivo real .

Então, você sabe, chame como quiser. O kernel não se importa - todas as referências de arquivo que ele manipulará lidarão com números de inode reais de qualquer maneira. O nome do arquivo é coisa para humanos consumo - se você quer torná-lo louco, bem, é o seu sistema de arquivos. Aqui, eu vou fazer algumas coisas loucas:

Primeiro, vou criar 20 arquivos e nomeá-los com nada além de espaços, cada nome de arquivo contendo mais um espaço que o anterior:

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

Isso é meio engraçado. Olhe para o meu ls:

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

Agora vou espelhar este diretório:

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

Aqui estão ../mirror/os conteúdos:

../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, mas talvez você esteja perguntando - mas que bom é isso? Como você pode dizer qual é qual? Como você pode ter certeza de vincular o número do inode certo ao nome do arquivo certo?

Bem...

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

SAÍDA

heyhey
heyhey

Veja, o número do inode contido ../mirror/"${tgt%% .*}"e o referenciado ./' 'referem-se ao mesmo arquivo. Eles descrevem o mesmo arquivo. Eles o nomeiam, mas nada mais. Na verdade, não há mistério, apenas alguns inconvenientes que você pode causar, mas que acabará por ter pouco ou nenhum efeito na operação do seu sistema de arquivos unix no final.

mikeserv
fonte