Eu tenho um monte de links simbólicos para outra unidade. Eu preciso mover todos os arquivos dessa unidade que são referenciados em outro lugar para que eu possa removê-lo.
Marty Trenouth
Respostas:
14
Para algumas definições de "fácil":
#!/bin/shset-e
for link;do
test -h "$link"||continue
dir=$(dirname "$link")
reltarget=$(readlink "$link")case $reltarget in/*) abstarget=$reltarget;;*) abstarget=$dir/$reltarget;;esac
rm -fv "$link"
cp -afv "$abstarget""$link"||{# on failure, restore the symlink
rm -rfv "$link"
ln -sfv "$reltarget""$link"}done
Execute este script com nomes de links como argumentos, por exemplo, através de find . -type l -exec /path/tos/script {} +
Obrigado pela edição, anon, mas o script faz nomes punho com espaços muito bem, citando variáveis em todos os lugares necessários. Mudar "$var"para "${var}"é um noop no sh / bash. Eu removi o bashism ( [[), o resto é compatível com o POSIX sh.
# Grawity #
Um método ainda mais robusto para lidar com falhas de links simbólicos é colocar cpem um arquivo temporário no mesmo diretório e depois em mv -fum arquivo temporário no original. Isso deve evitar problemas, como pessoas pressionando Ctrl-Cou o sistema de arquivos sendo preenchido entre os comandos rme cp(impedindo assim mesmo o lnfuncionamento do novo ). Os nomes de arquivos temporários são fáceis de localizar ls -apara limpeza posterior, se necessário.
Mr Fooz
Como uma observação lateral, eu realmente não me lembro por que não usei apenas abstarget=$(readlink -f "$link")o bloco de casos , mas pode ter sido por razões de portabilidade.
grawity
17
Pode ser mais fácil usar o tar para copiar os dados para um novo diretório.
-H (c and r mode only)Symbolic links named on the command line will
be followed; the target of the link will be archived, not the
link itself.
Você poderia usar algo assim
tar -hcf - sourcedir | tar -xf --C newdir
tar --help:-H,--format=FORMAT create archive of the given format
-h,--dereference follow symlinks; archive and dump the files they point to
Graças - quase o que eu precisava: Eu tinha que fazer algo como: cp -L files tmp/ && rm files && cp tmp/files . Se você esclarecer, você provavelmente vai ajudar mais pessoas ...
sage
5
"fácil" será uma função sua, provavelmente.
Provavelmente eu escreveria um script que usa o utilitário de linha de comando "find" para encontrar arquivos simbolicamente vinculados e depois chama rm e cp para remover e substituir o arquivo. Você provavelmente faria bem em também chamar a ação pela verificação de localização, para que haja espaço livre suficiente antes de mover o link sym também.
Outra solução pode ser montar o sistema de arquivos em questão através de algo que oculte os links sym (como o samba) e, em seguida, copie tudo disso. Mas, em muitos casos, algo assim introduziria outros problemas.
Uma resposta mais direta à sua pergunta é provavelmente "sim".
Editar: conforme a solicitação de informações mais específicas. De acordo com a página de manual do find , este comando listará todos os arquivos de links sym em uma profundidade de 2 diretórios, em /:
Para conseguir encontrar para executar algo em encontrá-lo:
find /-maxdepth 2-type l -exec ./ReplaceSymLink.sh {} \;
Acredito que isso chamará algum script que acabei de inventar e passará o nome do arquivo que você acabou de encontrar. Como alternativa, você pode capturar a saída find para o arquivo (use "find [blah]> symlinks.data", etc) e depois passe esse arquivo para um script que você escreveu para lidar com a cópia do original normalmente.
Isso é para encontrar os itens e o marcado como resposta é usado para substituir os links!
Marty Trenouth
3
Este é o oneliner que eu usei: suponha que todos os arquivos locais sejam links para outro arquivo em "source". Você pode refinar a seleção de arquivos com padrões ou "localizar". Por favor, entenda antes de usar.
para f em *; do cp --remove-destination source / $ f $ f; feito
que tal usar o readlink: para f em *; do cp ---- remove-destination "$ (readlink $ f)" "$ f"; feito
Diego
Sim, é uma boa ideia, mas você perde algum controle sobre a operação. Um limite da minha solução é que ele não funciona para arquivos com espaços em branco no meio ou para listas muito longas. Provavelmente a solução final é reunir o 'find --exec' acima com o 'remove destination'. Alguém quer tentar?
MastroGeppetto
espaços em branco no meio devem ser atenuados colocando "$ f" entre aspas duplas. Aqui está como eu o uso com "find & xargs" em vez de "for loop": find ./ -type l -print0 | xargs -0 -n1 -i sh -c 'cp --remove-destination $ (readlink "{ } ")" {} "'Publiquei como uma resposta separada para a visibilidade. superuser.com/a/1329543/499386
Diego #
2
find .-type l -exec cp --dereference --recursive '{}''{}'.dereferenced \;
Ele fará uma cópia de cada arquivo / pasta com link simbólico <filename>.dereferenced, o que é mais seguro (se menos conveniente) do que apenas substituí-los diretamente. Mover os dados copiados para os nomes dos arquivos dos links simbólicos é deixado como um exercício para o leitor.
Um pequeno aprimoramento ajudará a encontrar links simbólicos: para o lnk no `find. -tipo l`; do src = $ (readlink $ lnk) && rm $ lnk && mv $ src $ lnk; feito (não testado com a hierarquia, porém, ter cuidado com acentos graves)
Roman Susi
1
Eu tive o mesmo problema com o gwenview ao copiar links quando você normalmente espera que ele siga o link e copie o arquivo.
O que fiz para 'limpar' o diretório, seguindo todos os links e copiando todos os arquivos apontados para o diretório, foi criar um diretório inicial, executar por exemplo
"for file in `ls`; do cp -L $file scratchdir/$file; done; mv scratchdir/* ./"
isso é muito perigoso para colocar em um script, pois não há verificação, mas foi corrigido o meu problema.
Respostas:
Para algumas definições de "fácil":
Execute este script com nomes de links como argumentos, por exemplo, através de
find . -type l -exec /path/tos/script {} +
fonte
"$var"
para"${var}"
é um noop no sh / bash. Eu removi o bashism ([[
), o resto é compatível com o POSIX sh.cp
em um arquivo temporário no mesmo diretório e depois emmv -f
um arquivo temporário no original. Isso deve evitar problemas, como pessoas pressionandoCtrl-C
ou o sistema de arquivos sendo preenchido entre os comandosrm
ecp
(impedindo assim mesmo oln
funcionamento do novo ). Os nomes de arquivos temporários são fáceis de localizarls -a
para limpeza posterior, se necessário.abstarget=$(readlink -f "$link")
o bloco de casos , mas pode ter sido por razões de portabilidade.Pode ser mais fácil usar o tar para copiar os dados para um novo diretório.
Você poderia usar algo assim
fonte
tar -hcf - sourcedir | tar -xf - -C newdir
cp -L
é a solução mais simplescp
implementações copiarão diretórios.Se eu entendi corretamente, a
-L
bandeira docp
comando deve fazer exatamente o que você deseja.Basta copiar todos os links simbólicos e eles serão substituídos pelos arquivos para os quais eles apontam.
fonte
cp -L files tmp/ && rm files && cp tmp/files .
Se você esclarecer, você provavelmente vai ajudar mais pessoas ..."fácil" será uma função sua, provavelmente.
Provavelmente eu escreveria um script que usa o utilitário de linha de comando "find" para encontrar arquivos simbolicamente vinculados e depois chama rm e cp para remover e substituir o arquivo. Você provavelmente faria bem em também chamar a ação pela verificação de localização, para que haja espaço livre suficiente antes de mover o link sym também.
Outra solução pode ser montar o sistema de arquivos em questão através de algo que oculte os links sym (como o samba) e, em seguida, copie tudo disso. Mas, em muitos casos, algo assim introduziria outros problemas.
Uma resposta mais direta à sua pergunta é provavelmente "sim".
Editar: conforme a solicitação de informações mais específicas. De acordo com a página de manual do find , este comando listará todos os arquivos de links sym em uma profundidade de 2 diretórios, em /:
( isso foi encontrado aqui )
Para conseguir encontrar para executar algo em encontrá-lo:
Acredito que isso chamará algum script que acabei de inventar e passará o nome do arquivo que você acabou de encontrar. Como alternativa, você pode capturar a saída find para o arquivo (use "find [blah]> symlinks.data", etc) e depois passe esse arquivo para um script que você escreveu para lidar com a cópia do original normalmente.
fonte
-exec ./ReplaceSymLink.sh {} \;
Este é o oneliner que eu usei: suponha que todos os arquivos locais sejam links para outro arquivo em "source". Você pode refinar a seleção de arquivos com padrões ou "localizar". Por favor, entenda antes de usar.
Espero que isto ajude
fonte
Ele fará uma cópia de cada arquivo / pasta com link simbólico
<filename>.dereferenced
, o que é mais seguro (se menos conveniente) do que apenas substituí-los diretamente. Mover os dados copiados para os nomes dos arquivos dos links simbólicos é deixado como um exercício para o leitor.fonte
Usando algumas das idéias anteriores, o comando a seguir substituirá recursivamente todos os links simbólicos por uma cópia do original:
fonte
baseado em https://superuser.com/a/1301199/499386 da MastroGeppetto
fonte
Muitas respostas boas lá, mas eu desde que você estava procurando por algo fácil
fonte
Eu tive o mesmo problema com o gwenview ao copiar links quando você normalmente espera que ele siga o link e copie o arquivo.
O que fiz para 'limpar' o diretório, seguindo todos os links e copiando todos os arquivos apontados para o diretório, foi criar um diretório inicial, executar por exemplo
isso é muito perigoso para colocar em um script, pois não há verificação, mas foi corrigido o meu problema.
fonte
fonte
Eu fiz uma versão em uma linha, pois o meu hotel na web não permitia bash-scripts e funcionou bem para mim:
fonte