Truncar se necessário ao mover o arquivo para o sistema de arquivos com NAME_MAX mais curto

1

Eu quero mover veryverylongfilename.txt para um sistema de arquivos que tenha um NAME_MAX curto .

mv veryverylongfilename.txt /mnt/tiny me fornece um ENAMETOOLONG - erro do tipo:

mv: cannot stat '/mnt/tiny/veryverylongfilename.txt': File name too long

Qual comando devo usar para truncar o nome do arquivo, se necessário?

Seria ótimo se o comando pudesse manter a extensão. Além disso, seria bom evitar sobrescrever os arquivos existentes, por exemplo, ao mover veryverylongfilename1.txt then veryverylongfilename2.txt , usando qualquer tipo de identificador exclusivo no lugar dos últimos caracteres antes da extensão.

    
por Nicolas Raoul 15.08.2017 / 14:13

1 resposta

2

A seguinte função (testada no bash) tentará mover seu primeiro parâmetro para seu segundo parâmetro. Ele espera (e testa) o primeiro parâmetro para ser um arquivo e o segundo para ser um diretório.

A variável "namemax" local deve ser ajustada ao NAME_MAX do seu sistema de arquivos.

moveshort() {
  local namemax=8

  # simple sanity checks
  [ "$#" -eq 2 ] || return 1
  local src=$1
  [ -e "$src" ] || return 2
  local dest=$2
  [ -d "$dest" ] || return 3

  local extension=${src##*.}
  local basename=${src%.*}
  # the base name has ($namemax - $extension - 1)
  # characters available to it (1 for the period)
  local maxbase=$((namemax - ${#extension} - 1))

  # shorten the name, if necessary
  basename=${basename:0:maxbase}

  # echo "Shortened name: ${basename}.${extension}"
  # find a new name, if necessary
  if [ -e "${dest}/${basename}.${extension}" ]
  then
    local index=1
    local lenindex=${#index}
    #local newbase=${basename:0:-lenindex}
    local newbase=${basename:0:maxbase - lenindex}
    # loop as long as a conflicting filename exists and
    # we're not out of space in the filename for the index
    while [ -e "${dest}/${newbase}${index}.${extension}" -a "${#index}" -lt "$maxbase" ]
    do
      index=$((index + 1))
      lenindex=${#index}
      newbase=${newbase:0:maxbase - lenindex}
    done
    if [ -e "${dest}/${newbase}${index}.${extension}" ]
    then
      echo "Failed to find a non-colliding new name for $src in $dest" >&2
      return 4
    fi
    basename=${newbase}${index}
    # echo "new name = ${basename}.${extension}"
  fi

  # perform the move
  mv -- "$src" "${dest}/${basename}.${extension}"
}

Após as verificações de integridade, a função salva a extensão e o nome de arquivo base restante e, em seguida, determina quantos caracteres estão disponíveis para o nome do arquivo base a ser usado.

Se o nome de arquivo fornecido já for muito longo, cortamos os caracteres extras.

Se o nome abreviado já existir no destino, começamos o looping, começando em 1, gerando um novo nome de arquivo base até ficar sem espaço no nome de arquivo base ou encontrarmos um arquivo que não existe. O novo nome de arquivo base é espremido pelo índice conforme o índice cresce.

Se ficarmos sem espaço no nome do arquivo, a função exibe um erro e retorna; caso contrário, ele tentará executar o mv .

    
por 15.08.2017 / 15:22