27

Есть ли простой способ заменить все символические ссылки файлом, на который они ссылаются?

12 ответов12

17

Возможно, будет проще использовать tar для копирования данных в новый каталог.

-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.

Вы могли бы использовать что-то вроде этого

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
12

Если я вас правильно понял, флаг -L команды cp должен делать именно то, что вы хотите.

Просто скопируйте все символические ссылки, и он заменит их файлами, на которые они указывают.

12

Для некоторых определений "легкий":

#!/bin/sh
set -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

Запустите этот скрипт с именами ссылок в качестве аргументов, например, через find . -type l -exec /path/tos/script {} +

5

"Легко" будет функцией от вас, скорее всего.

Возможно, я бы написал скрипт, который использует утилиту командной строки find для поиска символически связанных файлов, а затем вызывает rm и cp, чтобы удалить и заменить файл. Вы, вероятно, преуспели бы в том, чтобы также вызывать действие, вызываемое проверкой поиска, что достаточно свободного места перед перемещением ссылки sym.

Другое решение может состоять в том, чтобы смонтировать файловую систему через что-то, что скрывает ссылки sym (например, samba), а затем просто скопировать все из этого. Но во многих случаях подобное может привести к другим проблемам.

Более прямой ответ на ваш вопрос, вероятно, "да".

Редактировать: согласно запросу для более конкретной информации. Согласно man-странице для find, эта команда выведет список всех файлов ссылок sym на глубину до 2 каталогов, из /:

find / -maxdepth 2 -type l -print

(это было найдено здесь)

Чтобы найти, чтобы выполнить что-то при поиске:

find / -maxdepth 2 -type l -exec ./ReplaceSymLink.sh {} \;

Я полагаю, что это вызовет какой-то скрипт, который я только что составил, и передам имя файла, который вы только что нашли. В качестве альтернативы, вы можете записать результаты поиска в файл (используйте «find [blah]> symlinks.data» и т.д.), А затем передать этот файл в сценарий, который вы написали, для корректного копирования оригинала.

2

Используя некоторые из предыдущих идей, следующая команда рекурсивно заменит каждую символическую ссылку на копию оригинала:

find . -type l -exec bash -c "echo 'Replacing {} ...';  cp -LR '{}' '{}'.dereferenced;  rm '{}';  mv '{}'.dereferenced '{}'" \;
2

Это единственная возможность, которую я использовал: предположим, что все локальные файлы являются ссылками на другой файл в "источнике". Вы можете уточнить выбор файла с помощью шаблонов или "найти". Пожалуйста, поймите, прежде чем использовать.

для f в *; do cp --remove-destination source/$ f $ f; сделанный

Надеюсь это поможет

2
find . -type l -exec cp --dereference --recursive '{}' '{}'.dereferenced \;

Создает копию каждого файла / папки с символьными ссылками в <filename>.dereferenced , что безопаснее (если менее удобно), чем просто их прямая замена. Перемещение скопированных данных в имена файлов символических ссылок оставлено читателю в качестве упражнения.

1

Там много хороших ответов, но я так как вы искали что-то легкое

for i in *; do link=$(readlink $i) && rm $i && mv $link $i; done
1

У меня была такая же проблема со ссылками на копирование в gwenview, когда вы обычно ожидали, что она перейдет по ссылке и скопирует файл.

То, что я сделал, чтобы «очистить» каталог, перейдя по всем ссылкам и скопировав все указанные файлы в каталог, - это создать «чистый» каталог, запустить, например,

"for file in `ls`; do cp -L $file scratchdir/$file; done; mv scratchdir/* ./" 

это слишком опасно для сценария, так как нет проверки, но это решило мою проблему.

1
find ./ -type l -print0|xargs -0 -n1 -i sh -c 'cp --remove-destination $(readlink "{}") "{}" '

основанный на https://superuser.com/a/1301199/499386 MastroGeppetto

1
for f in *; do cp --remove-destination $(readlink "$f") "$f"; done
0

Я сделал однострочную версию, так как мой веб-отель не разрешал bash-скрипты, и он работал нормально для меня:

before:
> find . -type l | wc -l
358

> for link in `find . -type l` ; do echo "$link : "; ls -al $link ; cp $link notalink; unlink $link; mv notalink $link ; ls -al $link; done
...

after:
> find . -type l | wc -l
0

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .