Como posso "revincular" muitos links simbólicos quebrados?

54

Eu tenho uma árvore de diretórios que possui vários links simbólicos para arquivos em /home... no entanto, mudei /homepara /mnt/homee preciso de uma maneira de "vincular novamente" todos os links simbólicos. Existe tal funcionalidade ou preciso escrever um script para fazer isso?

Como exemplo, eu tenho algo como o seguinte:

[root@trees ~]# ls -l /mnt/home/someone/something
total 4264
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 a -> /home/someone/someotherthing/a
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 b -> /home/someone/someotherthing/b
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 c -> /home/someone/someotherthing/c
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 d -> /home/someone/someotherthing/d
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 e -> /home/someone/someotherthing/e

/mnt/home/someone/something/subdir:
total 4264
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 a -> /home/someone/someotherthing/subdir/a
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 b -> /home/someone/someotherthing/subdir/b
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 c -> /home/someone/someotherthing/subdir/c
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 d -> /home/someone/someotherthing/subdir/d
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 e -> /home/someone/someotherthing/subdir/e

Eu quero um comando que encontre todos os links simbólicos e vincule novamente aos mesmos lugares, mas por baixo, em /mnt/homevez de/home

Existe um comando desse tipo?

Josh
fonte

Respostas:

55

Não há comando para redirecionar um link simbólico, tudo o que você pode fazer é removê-lo e criar outro. Supondo que você tenha utilitários GNU (por exemplo, no Linux ou Cygwin não incorporado), você pode usar o -lnameprimário de findpara corresponder aos links simbólicos pelo destino e readlinkler o conteúdo do link. Não testado:

find /mnt/home/someone/something -lname '/home/someone/*' \
     -exec sh -c 'ln -snf "/mnt$(readlink "$0")" "$0"' {} \;

Seria melhor tornar esses links simbólicos relativos. Há um pequeno utilitário conveniente chamado symlinks(originalmente por Mark Lords, agora mantido por J. Brandt Buckley), presente em muitas distribuições Linux. Antes da mudança, ou depois de restaurar os links válidos, conforme descrito acima, execute symlinks -c /mnt/home/someone/somethinga conversão de todos os links simbólicos absolutos no diretório especificado em links simbólicos relativos, a menos que eles cruzem um limite do sistema de arquivos.

Gilles 'SO- parar de ser mau'
fonte
Sem ofensas, esse é um ótimo argumento, mas a substituição de cordas de Bash provavelmente poderia fazer alguma mágica na mudança de caminho e seria mais fácil.
0xC0000022L
@STATUS_ACCESS_DENIED Como assim? A única operação de string é preceder /mntum caminho; você não precisa de operação mais sofisticada que a concatenação.
Gilles 'SO- stop be evil' em
@ Gilles: desculpe, eu estava pensando mais sobre a sua observação com os caminhos relativos. Para uma "tradução" exata do seu exemplo, você está certo.
0xC0000022L
13

Eu sei que isso não é exatamente o que o autor está solicitando, mas parece que eles já têm sua resposta, então estou adicionando isso a outras pessoas como eu, que tropeçam na pergunta.

O seguinte deve ajudar se for necessária uma solução mais flexível, como ter vários links simbólicos quebrados que podem ser corrigidos substituindo parte dos destinos do link simbólico.

por exemplo. Após uma mudança de nome de usuário, para substituir o nome de usuário antigo pelo novo nome de usuário no destino de muitos links, após a movimentação já ter sido feita. Crie um script chamado replace-simlinks mostrado abaixo:

#!/bin/bash
link=$1
# grab the target of the old link
target=$(readlink -- "$1")

# replace the first occurrence of oldusername with newusername in the target string
target=${target/oldusername/newusername}

# Test the link creation
echo ln -s -- "$target" "$link"

# If the above echo shows the correct commands are being issued, then uncomment the following lines and run the command again
#rm $link
#ln -s "$target" "$link"

e chame-o com o seguinte comando:

find /home/newusername/ -lname '/home/oldusername/*' -exec ~/bin/replace-simlinks {} \;

Espero que isso ajude alguém

edit: Obrigado Gilles pelo kickstart deste script e pela dica sobre o uso do script symlinks para tornar os links relativos.

Gerry
fonte
11
Acho essa solução melhor porque ela usa uma substituição de string, o que ajuda nos casos em que você precisa alterar o nome de uma pasta no meio do caminho. A solução também é bastante fácil de modificar para executar transformações mais complexas, se necessário.
precisa
Eu recomendo citar os argumentos para a substituição de string, pois isso deve ser feito para usar barras, por exemplo, para o caminho na pergunta do OP. target=${target/"/home"/"/mnt/home"}Muito útil, no entanto. Obrigado.
Walter Nissen 29/11
3

Crie /homecomo um link simbólico para /mnt/homee todos os links simbólicos existentes serão válidos novamente.

Keith Thompson
fonte
2
Bind de montagem muitas vezes tende a ser menos frágil do que links simbólicos em cenários onde os programas estão cientes de links simbólicos e agir de forma diferente, dependendo do fato ...
0xC0000022L