заменить все символические ссылки на оригинальные - PullRequest
28 голосов
/ 24 августа 2011

У меня следующая структура каталогов

/symdir
  sym1 -> ../dir1
  sym2 -> ../dir2
  hello.txt

А потом

/dir1
  some
  files
  here
/dir2
  more
  files

Я хотел бы заменить символические ссылки в symdir (sym1, sym2) на оригиналы. * 1007 Т.е. *

some_awesome_bash_func symdir symdir_output

создаст

/symdir_output
  /dir1
    some
    files
    here
  /dir2
    more
    files
  hello.txt

Как бы мне этого добиться?

Ответы [ 7 ]

64 голосов
/ 01 октября 2012

Мой очень личный трюк:

sed -i '' **/*

Обратите внимание, что я использую **, который использует опцию bash globstar, возможно, вам придется включить его заранее:

shopt -s globstar
23 голосов
/ 24 августа 2011

Вы можете легко сделать это с помощью rsync:

rsync symdir/ symdir_output/ -a --copy-links -v

(- средство, сохраняющее практически все детали файлов, --copy-links переопределяет -a, чтобы превратить символические ссылки в реальные файлы / каталоги,и -v для многословия)

Редактировать:

Извините, мое решение не выполняет то, что вы просили.Это сохранит имена символической ссылки вместо использования имен назначения.symdir_output будет иметь sym1 и sym2 вместо dir1 и dir2 (хотя sym1 и sym2 будут настоящей копией dir1 и dir2).Надеюсь, это все еще работает для вас.

12 голосов
/ 26 июля 2013

связанный ответ, это решение сохраняет файл в его оригинальном месте и создает копию вместо символической ссылки

#/bin/bash

for f in $(find . -maxdepth 1 -type l)
do
    cp --remove-destination $(readlink -e $f) $f
done
10 голосов
/ 24 августа 2011

Наверное, не лучший способ, но он работает:

#!/usr/bin/bash

for link in $(find /symdir -type l)
do
  loc="$(dirname "$link")"
  dir="$(readlink "$link")"
  mv "$dir" "$loc"
  rm "$link"
done
6 голосов
/ 05 октября 2016

тл; др: гораздо более общий, гораздо более надежный ответ:

find -type l -exec sh -c 'PREV=$(realpath -- "$1") && rm -- "$1" && cp -ar -- "$PREV" "$1"' resolver {} \;

Подход "rsync-to-other-destination" строго превосходит и обычно приводит к лучшему дизайну.

Ответ @PinkFloyd не совсем работает с необычными именами файлов, «скрытыми» символическими ссылками или символьными каталогами. Я пришел сюда, потому что хотел разрешить каталог-символические ссылки, поэтому я ожидаю, что другие тоже найдут этот вопрос по этой причине. Кроме того, моя версия cp (GNU coreutils 8.25) неправильно обрабатывает --remove-destination ответа @ PinkFloyd на работу с каталогами. Таким образом, этот ответ использует руководство rm.

Также обратите внимание:

  • отсутствие -rf. Это связано с тем, что символическая ссылка не является каталогом и не требует -r. И если у вас нет символических ссылок с ограниченными разрешениями (зачем вам это вообще нужно ?!), вам также не понадобится -f.
  • realpath прекрасно в этом контексте, потому что это позволяет нам узнать фактическое местоположение в текущей системе, в текущем контексте, и больше ничего не имеет значения. Этот путь не будет записан на диск, поэтому это не ошибка.
  • строка resolver предназначена для sh. См man sh.
  • двойные тире везде необходимы, если какая-нибудь символическая ссылка называется --version или аналогичной.
  • из-за предзаказа find («родительский каталог указан где-то перед его содержимым»), это сначала заменит родительский каталог, а затем любые символические ссылки в каталоге символических ссылок. Так что это будет прекрасно работать с «сложенными» символическими ссылками.
1 голос
/ 10 октября 2017

Я сделал это следующим образом:

ls -la | awk '/-\>/{system("rm "$10); system("cp "$12" .")}'

Как это работает:

ls -la выводит что-то вроде этого:

lrwxr-xr-x  1 username  groupname   44 10 Oct 12:17 Queue.swift -> ../../../Platform/DataStructures/Queue.swift

Столбец 10 равен Queue.swift это имя локального файла.
Столбец 12 - это ../../../Platform/DataStructures/Queue.swift, который является именем цели ссылки

Первая часть команды awk - '/-\>/', что означает "match"строки, содержащие -> с использованием регулярного выражения

Следующая часть команды awk - это два вызова system

First system("rm "$10), который расширяется до system("rm Queue.swift").
Thisприведет к удалению исходного файла (символической ссылки)

Второй - system("cp "$12" ."), который расширяется до system("cp ../../../Platform/DataStructures/Queue.swift .")

Собирая все вместе, что происходит для каждого файла (который являетсясимволическая ссылка), сначала мы удаляем символическую ссылку, затем копируем целевой файл на его место.


Хотя это не является частью исходного вопроса, я использовал это в сочетании с git. Если вам случитсяделать это тоже, вы можете запустить git status . впоследствии, и вы должны увидеть кучу изменений типа (и ничего эse), вот так:

typechange: Queue.swift
0 голосов
/ 01 сентября 2018

вот немного более общее решение, основанное на @Daniel Haley

также сохраняет символические ссылки для справки и просит пользователя выбрать каталог для редактирования.

ls
read -p 'Which directory do you want to update?: ' linkdir

pushd $linkdir

for linkname in $(find ./ -type l)
do
  orig=$(readlink $linkname)
  mv $linkname ${linkname}.linkbak
  cp $orig $linkname
done

popd
...