Mover um arquivo e substituí-lo por um link simbólico

16

Alguém pode me dar um comando que:

  • mover um arquivo para um novo diretório
  • e deixe um link simbólico no local antigo em direção ao novo
Yo B.
fonte

Respostas:

19

mvmove um arquivo e ln -scria um link simbólico; portanto, a tarefa básica é realizada por um script que executa esses dois comandos:

#!/bin/sh
mv -- "$1" "$2"
ln -s -- "$2" "$1"

Existem algumas ressalvas. Se o segundo argumento for um diretório, mvo arquivo será movido para esse diretório, mas ln -scriará um link para o diretório, e não para o arquivo movido.

#!/bin/sh
set -e
original="$1" target="$2"
if [ -d "$target" ]; then
  target="$target/${original##*/}"
fi
mv -- "$original" "$target"
ln -s -- "$target" "$original"

Outra ressalva é que o primeiro argumento para ln -sé o texto exato do link simbólico. É relativo à localização do destino, não ao diretório em que o comando é executado. Se o local original não estiver no diretório atual e o destino não for expresso por um caminho absoluto, o link estará incorreto. Nesse caso, o caminho precisa ser reescrito. Nesse caso, criarei um link absoluto (um link relativo seria preferível, mas é mais difícil de acertar). Este script pressupõe que você não possui nomes de arquivos que terminam em um caractere de nova linha.

#!/bin/sh
set -e
original="$1" target="$2"
if [ -d "$target" ]; then
  target="$target/${original##*/}"
fi
mv -- "$original" "$target"
case "$original" in
  */*)
    case "$target" in
      /*) :;;
      *) target="$(cd -- "$(dirname -- "$target")" && pwd)/${target##*/}"
    esac
esac
ln -s -- "$target" "$original"

Se você tiver vários arquivos, processe-os em um loop.

#!/bin/sh
while [ $# -gt 1 ]; do
  eval "target=\${$#}"
  original="$1"
  if [ -d "$target" ]; then
    target="$target/${original##*/}"
  fi
  mv -- "$original" "$target"
  case "$original" in
    */*)
      case "$target" in
        /*) :;;
        *) target="$(cd -- "$(dirname -- "$target")" && pwd)/${target##*/}"
      esac
  esac
  ln -s -- "$target" "$original"
  shift
done
Gilles 'SO- parar de ser mau'
fonte
1
Obrigado Gilles, pelo roteiro e pelas explicações. Vou tentar entender isso!
Yo B.
Este deve ser marcado como a resposta certa
Sridhar Sarnobat
Para tornar essa resposta ainda mais impressionante, rsync --remove-source-filespode ser mais informativo para os usuários que estão movendo um arquivo grande de um disco, o que pode levar algum tempo.
Sridhar Sarnobat
Eu acho que você deve chamar sh com -e, para que ele interrompa os erros, por exemplo, se você parar o comando mv porque já existe um arquivo
Alex
2

Coloque isso no arquivo .sh e torne-o executável ( chmod +x filename):

#!/bin/bash

mv "$1" "$2"
ln -s "$2" "$1"

Exemplo de uso:

./test.sh asdf otherdir/asdf

Observe que isso não faz verificações de segurança, etc. Dependendo da complexidade da sua tarefa, isso pode ser suficiente.

MatthewRock
fonte
Obrigado Matthew, isso funciona perfeitamente quando aplicado em um arquivo. Mas você pode me ajudar a generalizar isso para dois diretórios como este: ./test.sh .mozila/firefox/zotero/*/*.pdf MyBbliography/*.pdf. A *não parece estar a trabalhar com o seutest.sh . Você tem uma solução alternativa? Thx
Yo B.
2
O script de MatthewRock do @kadok funciona apenas para um único arquivo, e o destino deve ser um caminho absoluto, ou a fonte deve estar no diretório atual.
Gilles 'SO- stop be evil'
Além disso, não funcionará se $ 1 for um arquivo, mas $ 2 for um diretório.
Sridhar Sarnobat
0

Eu geralmente uso a função de uma linha:

function ml() { mkdir -p "$(dirname "$1")" && rsync -aP --no-links "$1" "$2" && ln -sf "$2" "$1" }

O uso é semelhante ao mv ou cp:

ml old_file target_dir/new_file_name

Dividindo:

  • mkdir -p "$(dirname "$1")" - crie o diretório de destino se ele ainda não existir
    • dirname "$1" - obtém o componente de diretório do caminho (retira o nome do arquivo)
  • rsync -aP --no-links "$1" "$2"- copie o arquivo para o destino. Substitua por mv "$1" "$2"se os dois arquivos estiverem no mesmo sistema de arquivos para obter melhor desempenho.
    • -a- preservar a propriedade e todas as outras permissões. Você pode ajustar isso para preservar apenas os componentes que deseja.
    • -P - mostrar progresso.
    • --no-links - não copie links - isso significa que você pode executar este comando quantas vezes quiser no mesmo arquivo e nunca perderá o arquivo substituindo acidentalmente o arquivo de destino com um link simbólico.
  • ln -sf "$2" "$1" - sobrescreva o arquivo antigo com um link simbólico para o novo arquivo
    • -s - use links simbólicos
    • -f - sobrescrever o arquivo antigo
user60561
fonte