Uso de nomes de arquivos terminados em um período

6

Por que o Unix permite arquivos com um período no final do nome? Existe algum uso para isso?

Por exemplo:

filename.

Estou perguntando porque tenho uma função simples que ecoa a extensão de um arquivo.

ext() {
  echo ${1##*.}
}

Mas sabendo que ele não imprimirá nada se o nome do arquivo terminar em . , imaginei se seria mais confiável escrever:

ext() {
  extension=${1##*.}
  if [ -z "$extension" ]; then
    echo "$1"
  else
    echo "$extension"
  fi
}

É claro que isso depende do que você está tentando realizar, mas se um . no final do nome do arquivo não for permitido, eu não teria imaginado nada em primeiro lugar.

    
por Jorge Bucaran 08.03.2015 / 07:20

2 respostas

26

Os nomes de arquivos Unix são apenas sequências de bytes e podem conter qualquer byte, exceto / e NUL em qualquer posição. Não há um conceito embutido de uma "extensão", como existe no Windows e em seus sistemas de arquivos, e, portanto, não permite que os nomes de arquivos terminem (ou iniciem) com qualquer caractere que possa aparecer neles geralmente - um . é não é mais especial que um x .

Por que o Unix permite arquivos com um período no final do nome? "Uma seqüência de bytes" é uma definição simples e não-excludente de um nome quando não há razão motivadora para contar algo, o que não havia. Fazer e aplicar uma regra para excluir algo especificamente é mais trabalho.

Existe algum uso para isso? Se você quiser fazer um arquivo com esse nome, com certeza. Existe um uso para um nome de arquivo terminado em x ? Eu não posso dizer que eu geralmente faria um nome de arquivo com um . no final, mas ambos . e x são explicitamente parte do conjunto de caracteres de nome de arquivo portátil que é necessário para ser universalmente suportado, e nenhum deles é especial de forma alguma, por isso, se eu tivesse um uso para ele (talvez para um mecanismo mecanicamente- codificação gerada), então eu poderia, e eu poderia confiar nele trabalhando.

Além disso, os nomes de arquivo especiais . (ponto) e .. (ponto-ponto), que se referem aos diretórios atual e pai, são obrigatório pelo POSIX, e ambos terminam com . . Qualquer código que lide com nomes de arquivos em geral precisa abordá-los de qualquer maneira.

    
por 08.03.2015 / 07:44
5

A verdadeira questão é, por que qualquer sistema operacional coloca significância em '.' ? Não há motivos técnicos para isso, é apenas um padrão que pode ajudá-lo a assumir o tipo de arquivo sem verificar.

Se você renomear um arquivo MP3 para .txt e tentar abri-lo nas janelas, verá imediatamente por que essa idéia tem desvantagens: de repente você "não consegue" abrir o arquivo corretamente. Tecnicamente falando, sem quaisquer considerações de velocidade e assim por diante, a "melhor" maneira provavelmente seria determinar o tipo de arquivo antes de decidir o que fazer com ele, já que as extensões são facilmente confusas e podem causar problemas.

O motivo pelo qual o linux não se importa com um ponto no nome é a mesma razão que uma pessoa que não usa computador não: não há diferença inerente entre um período e qualquer outro caractere além do fato de que alguns programas codificado para ver esse período e tratá-lo especialmente.

Supondo que você realmente quer apenas a extensão (que não é o que ambos os seus snippets fazem), você poderia usar isto:

ext(){
    extension=
    [[ $1 =~ \. ]] && extension="${1##*.}"
    echo "$1 -> ${extension:-No extension}"
}

ext something.    # something. -> No extension
ext something.txt # something.txt -> txt
ext something     # something -> No extension
ext som.thing.mp3 # som.thing.mp3 -> mp3
ext .whatever     # .whatever -> whatever

* Observe esse último.

Se você realmente quiser retornar o nome do arquivo quando não houver nenhuma extensão, como seu código, não há razão para usar o segundo snippet de estilo SH longo que você tem. Você escreveu:

ext() {
  extension=${1##*.}
  if [ -z "$extension" ]; then
    echo "$1"
  else
    echo "$extension"
  fi
}

O que é realmente apenas:

ext(){
 extension="${1##*.}"
 # This line is what your first snippet is doing: 
 # echo "$extension"
 # This line is what your second snippet is doing:
 [[ $extension ]] && echo "$extension" || echo "$1"
}

O que é realmente apenas:

# First snippet
ext(){
 echo "${1##*.}"
}

# Second snippet
ext(){
 extension="${1##*.}"
 echo "${extension:-$1}"
}

Você não pode dar como certo qualquer coisa que os usuários possam inserir basicamente. Se você quiser ver que tipo de arquivo realmente é, tente o comando file. Porque analisar nomes de arquivos para tentar descobrir o tipo de arquivo não é a única maneira de eliminar esse gato. Você pode até mesmo ter um nome de arquivo no linux chamado simplesmente: \

    
por 08.03.2015 / 12:29

Tags