Как я могу редактировать символические ссылки?

64

Мое базовое понимание символической ссылки - это специальный файл, файл, содержащий строковый путь к другому файлу. VFS ядра абстрагирует многое из этого, но есть ли причина, по которой символические ссылки кажутся невозможными для редактирования?

Другими словами: я могу отредактировать символическую ссылку? Если нет, то почему?


Я понимаю, что существуют различные способы замены символических ссылок (в настоящее время в разделе ответов есть две альтернативы), но было бы интересно получить объяснение того, почему замена кажется единственным способом справиться с символическими ссылками. Почему вы не можете просто изменить, куда они указывают?

Oli
источник
Ваше понимание немного ограничено; единственная причина, по которой он называется «файлом», заключается в том, что лучшего слова для этого нет.
Шадур
5
В отличие от смущающего зверства, являющегося вариантом windows, символические ссылки в стиле posix работают на / в самом уровне файловой системы. Единственный способ отредактировать один - это отредактировать файловую систему напрямую - и, как правило, это того не стоит.
Шадур
Файлы @Shadur .lnk на самом деле не являются символическими ссылками для начала (а NTFS имеет правильные символические ссылки начиная с Vista); они больше похожи на ярлыки для выполнения команд, будь то изменение в определенной папке или запуск программы с определенными аргументами и с определенным CWD.
JAB

Ответы:

36

Учитывая, что он -fпросто выполняет тихую замену, вы можете выполнить атомарную замену с помощью mv -T(-T заставляет это работать, даже если /loc.../link является каталогом) :

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

linkname доступен на протяжении всего процесса.

Oli
источник
7
Это дает вам атомную замену, хотя вы по-прежнему делаете замену, а не редактируете (новая ссылка имеет новый номер инода).
psusi
2
@psusi Я полностью согласен, это технически чуть лучше, чем другой ответ в некоторых сценариях.
Оли
Если вы перенаправляете ссылку на другое место назначения, то изменение ее номера inode кажется небольшим изменением.
Ams
4
Это предполагает, что linknameэто не символическая ссылка на каталог. Чтобы избежать этого, используйте -Tопцию, mvесли в GNU или -hво FreeBSD. Обратите внимание, что подобное ln -sfне сохраняет права ссылки (в системах, где они значимы).
Стефан Шазелас
Еще одно решением для изменения линка для каталога является использование -nопции , например: ln -sfn DESTINATION_DIRECTORY LINK_NAME. Узнайте больше на askubuntu.com/a/186227/69004
sobi3ch
22

Если под редактированием вы хотите изменить файл, на который он указывает, то да, вы можете:

$ 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

-fПараметр ( --force) при передаче в пер это заставляет его вызвать unlink()системный вызов прямо передsymlink()

Взято из следующего ответа переполнения стека .

NlightNFotis
источник
9
Я думаю, это сомнительно, если это можно рассматривать как «редактировать», так как unlink (); symlink (); не является атомарным, поэтому существует крошечный промежуток времени, в течение которого ссылка не существует.
повтор
@ mauro.stettler Да, вы правы. Но я думаю, что это зависит от вашей точки зрения. Если вы принимаете во внимание только конечный результат, то, возможно, вы могли бы рассмотреть его как отредактированный, без каких-либо других вещей.
NlightNFotis
1
В цитируемом разделе статьи Unix Time Sharing System описаны жесткие ссылки. Они полностью отличаются от символических ссылок (символических ссылок), о которых спрашивал ОП.
Ансгар Эстерманн
4
Обратите внимание, что предполагается, testчто цель не является каталогом. В противном случае ln -s -f .profile testсоздаст .profileсимволическую ссылку в этом каталоге. У GNU lnесть -Tвозможность избежать этого.
Стефан Шазелас
9

Символические ссылки должны быть изменены атомарно. Если вы наполовину пишете их, они не сработают. Содержимое символической ссылки довольно мало (не более 4095 символов в Linux: максимальная длина пути к файлу), поэтому нет смысла редактировать часть символической ссылки на уровне ядра. Поэтому ядро ​​не предлагает никакого интерфейса для редактирования символической ссылки, только интерфейс для создания новой, symlinkсистемный вызов (плюс универсальный интерфейс unlinkдля удаления любого файла).

symlinkСистемный вызов только создает новую символическую ссылку, он не удаляет существующий файл. Это раздражает, но согласуется с другими системными вызовами для создания файлов, таких как open(которые могут создать новый файл или обрезать существующий файл, но не заменить существующий файл вновь созданным файлом) и mkdir.

В оболочке, как вы обнаружили , хотя вы не можете атомарно заменить символическую ссылку lnкомандой ( ln -sfотсоединяет предыдущий файл, а затем создает символическую ссылку), вы можете сделать это, сначала создав символическую ссылку под временным именем и затем переместить его на место.

tmp=$(TMPDIR=$(dirname -- "$link") mktemp)
ln -sf -- "$target" "$tmp"
mv -f "$tmp" "$link"
Жиль "ТАК - перестань быть злым"
источник
2
mv -f(как ln -sf) не будет делать то, что вы хотите, если $linkуказывает на каталог. У GNU ln и mv есть -Tдля этого. mv(переименовать системный вызов) всегда будет изменять inode, в $linkто время как ln -sfT(unlink + symlink) может использовать то же самое.
Стефан Шазелас
0

Технически, нет встроенной команды для редактирования существующей символической ссылки. Это может быть легко достигнуто с помощью нескольких коротких команд.

Вот небольшая функция bash / zsh, которую я написал для обновления существующей символической ссылки:

# -----------------------------------------
# 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
источник
Извините, но вы «ответ» только отдаленно связаны с заданным вопросом.
user2233709
Привет @ user2233709 - на вопрос пользователя « Как я могу отредактировать символические ссылки? » Был дан четкий ответ в первом предложении, а также в предложении решения. Не могли бы вы уточнить?
blizzrdof77
2
Вы действительно прочитали вопрос? Речь идет о том, можно ли изменить символическую ссылку, а не заменить ее. Предлагаемое вами «решение» - это скрипт, который заменяет символическую ссылку.
user2233709
0

Предположим, что linkname существует в результате выполнения (в прошлом):

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

Затем есть три способа изменить символическую ссылку:

  • Используйте ln с -fсилой и даже для каталогов -n(inode может быть использован повторно):

    ln -sfn /some/new/path linkname
    
  • Удалите символическую ссылку и создайте новую (даже для каталогов):

    rm linkname; ln -s /some/new/path linkname
    
  • создайте новую символьную ссылку, затем mv(атомарное изменение даже для каталогов):

    ln -s  /some/new/path newlinkname
    mv -fT newlinkname linkname             # linkname remains after the command
    
Исаак
источник