Como posso editar links simbólicos?

64

Meu entendimento básico de um link simbólico é como um arquivo especial, um arquivo que contém um caminho de string para outro arquivo. O VFS do kernel abstrai muito disso, mas há alguma razão pela qual os links simbólicos parecem impossíveis de editar?

Em outras palavras: posso editar um link simbólico? Se não, por que não?


Entendo que existem várias maneiras de substituir os links simbólicos (duas alternativas estão atualmente na seção de respostas), mas seria interessante obter uma explicação sobre por que a substituição parece ser a única maneira de lidar com links simbólicos. Por que você não pode simplesmente mudar para onde eles apontam?

Oli
fonte
Sua compreensão é um pouco limitada; o único motivo pelo qual é chamado de 'arquivo' é porque não há uma palavra melhor para ele.
Shadur
5
Diferente da atrocidade embaraçosa que é a variante do Windows, os links simbólicos no estilo posix operam na / na própria camada do sistema de arquivos. A única maneira de editar um seria editar o sistema de arquivos diretamente - e geralmente não vale a pena.
Shadur
Os arquivos @Shadur .lnk não são realmente links simbólicos para começar (e o NTFS possui links simbólicos adequados desde o Vista); são mais parecidos com atalhos para executar comandos, seja alterando para uma pasta específica ou iniciando um programa com argumentos específicos e com um determinado CWD.
JAB

Respostas:

36

Dado que -fapenas faz uma substituição silenciosa, você pode fazer uma substituição atômica com mv -T(-T faz funcionar mesmo que /loc.../link seja um diretório) :

ln -s /location/to/link linkname
# ... 
ln -s /location/to/link2 newlink
mv -T newlink linkname

linkname está acessível durante todo o processo.

Oli
fonte
7
Isso fornece a substituição atômica, embora você ainda esteja fazendo uma substituição em vez de editar (o novo link tem um novo número de inode).
Psusi
2
@psusi Concordo plenamente, é apenas uma opção tecnicamente ligeiramente melhor do que a outra resposta em alguns cenários.
Oli
Se você estiver redirecionando o link para outro destino, alterar o número do inode parece uma pequena alteração.
30313
4
Isso pressupõe que linknamenão é um link simbólico para um diretório. Use a -Topção para mvse no GNU ou -hno FreeBSD para evitar isso. Observe que assim ln -sfnão preserva as permissões do link (nos sistemas em que são significativos).
Stéphane Chazelas
Outra solução para a mudança link simbólico para o diretório é usar -nopções, por exemplo: ln -sfn DESTINATION_DIRECTORY LINK_NAME. Leia mais em askubuntu.com/a/186227/69004
sobi3ch
22

Se por edição, você pretende alterar o arquivo para o qual aponta, então sim, você pode:

$ ln -s .bashrc test
$ ls -al test
lrwxrwxrwx 1 pascal pascal 7 2009-09-23 17:12 test -> .bashrc
$ ln -s .profile test
ln: creating symbolic link `test': File exists
$ ln -s -f .profile test
$ ls -al test
lrwxrwxrwx 1 pascal pascal 8 2009-09-23 17:12 test -> .profile

O -fparâmetro ( --force) quando passado para ln faz com que ele chame a chamada do unlink()sistema logo antessymlink()

Retirado da seguinte resposta de estouro de pilha .

NlightNFotis
fonte
9
Eu acho que é questionável se isso pode ser considerado como "editar", pois unlink (); symlink (); não é atômico, portanto, há uma quantidade minúscula de tempo durante a qual o link não existe.
repetir
@ mauro.stettler Sim, você está certo. Mas acho que isso depende da sua perspectiva. Se você levar em conta apenas o resultado final, talvez seja possível editá-lo como editado, sem considerar outras coisas.
N
11
A seção citou o papel Sharing System Unix Tempo descreve rígidos ligações. Eles são totalmente diferentes dos links simbólicos (links simbólicos) sobre os quais o OP perguntou.
Ansgar Esztermann 30/08/13
4
Observe que ele assume que testo destino não é um diretório. Caso contrário ln -s -f .profile test, criaria um .profilelink simbólico nesse diretório. O GNU lntem uma -Topção para evitar isso.
Stéphane Chazelas
9

Links simbólicos precisam ser modificados atomicamente. Se você estiver no meio da escrita, eles não funcionarão. O conteúdo de um link simbólico é muito pequeno (no máximo 4095 caracteres no Linux: o comprimento máximo de um caminho para um arquivo), portanto, não faria sentido editar parte de um link simbólico no nível do kernel. Portanto, o kernel não oferece nenhuma interface para editar um link simbólico, apenas uma interface para criar um novo, a symlinkchamada do sistema (mais a interface genérica unlinkpara remover qualquer arquivo).

A symlinkchamada do sistema cria apenas um novo link simbólico, não remove nenhum arquivo existente. Isso é irritante, mas consistente com outras chamadas do sistema para criar arquivos como open(que pode criar um novo arquivo ou truncar um arquivo existente, mas não substituir um arquivo existente por um arquivo recém-criado) e mkdir.

No shell, como você descobriu , embora não seja possível substituir atomicamente um link simbólico pelo lncomando ( ln -sfdesvincula o arquivo anterior e cria o link simbólico), você pode fazer isso criando primeiro um link simbólico com um nome temporário e em seguida, movendo-o no lugar.

tmp=$(TMPDIR=$(dirname -- "$link") mktemp)
ln -sf -- "$target" "$tmp"
mv -f "$tmp" "$link"
Gilles 'SO- parar de ser mau'
fonte
2
mv -f(like ln -sf) não fará o que você deseja se $linkapontar para um diretório. GNU ln e mv têm um -Tpara isso. mv(renomear chamada do sistema) sempre alterará o inode $linkenquanto ln -sfT(desvincular + link simbólico) pode reutilizar o mesmo.
Stéphane Chazelas
0

Tecnicamente, não há comando interno para editar um link simbólico existente. Pode ser facilmente alcançado com alguns comandos curtos.

Aqui está uma pequena função bash / zsh que escrevi para atualizar um link simbólico existente:

# -----------------------------------------
# Edit an existing symbolic link
#
# @1 = Name of symbolic link to edit
# @2 = Full destination path to update existing symlink with 
# -----------------------------------------
function edit-symlink () {
    if [ -z "$1" ]; then
        echo "Name of symbolic link you would like to edit:"
        read LINK
    else
        LINK="$1"
    fi
    LINKTMP="$LINK-tmp"
    if [ -z "$2" ]; then
        echo "Full destination path to update existing symlink with:"
        read DEST
    else
        DEST="$2"
    fi
    ln -s $DEST $LINKTMP
    rm $LINK
    mv $LINKTMP $LINK
    printf "Updated $LINK to point to new destination -> $DEST"
}
blizzrdof77
fonte
Desculpe, mas você "responde" está apenas remotamente relacionado à pergunta.
user2233709
Olá, @ user2233709 - a pergunta do usuário " Como posso editar links simbólicos? " Foi claramente respondida na primeira frase e também fornecendo uma solução. Você se importaria de elaborar?
blizzrdof77
2
Você realmente leu a pergunta? É sobre se é possível modificar um link simbólico, em vez de substituí- lo. Sua "solução" proposta é um script que substitui um link simbólico.
user2233709
0

Suponha que o nome do link exista como resultado de ter feito (no passado):

 ln -s   /the/path/to/a/file   linkname

Em seguida, existem três maneiras de alterar o link simbólico:

  • Use ln com -fforça e até para diretórios -n(o inode pode ser reutilizado):

    ln -sfn /some/new/path linkname
    
  • Remova o link simbólico e crie um novo (mesmo para diretórios):

    rm linkname; ln -s /some/new/path linkname
    
  • crie um novo link simbólico e, em seguida, mvele (alteração atômica mesmo para diretórios):

    ln -s  /some/new/path newlinkname
    mv -fT newlinkname linkname             # linkname remains after the command
    
Isaac
fonte