Mam kilka symbolicznych linków do innego dysku. Potrzebuję przenieść wszystkie pliki z tego dysku, do których istnieją odniesienia w innym miejscu, aby móc je usunąć.
Marty Trenouth
Odpowiedzi:
14
W przypadku niektórych definicji „łatwego”:
#!/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
Uruchom ten skrypt z nazwami łączy jako argumentami, np. Poprzez find . -type l -exec /path/tos/script {} +
Dzięki za edycję, anon, ale skrypt dobrze sobie radzi z nazwami plików ze spacjami, cytując zmienne we wszystkich niezbędnych miejscach. Zmiana "$var"na "${var}"to noop w sh / bash. Usunąłem jeden bashism ( [[), reszta jest kompatybilna z POSIX sh.
grawitacja
Jeszcze bardziej niezawodną metodą radzenia sobie z awariami dowiązań symbolicznych jest cputworzenie pliku tymczasowego w tym samym katalogu, a następnie mv -fpliku tymczasowego do oryginału. Powinno to zabezpieczyć się przed problemami takimi jak przytrzymywanie się ludzi Ctrl-Club zapełnianie się systemu plików między poleceniami rmi cp(zapobiegając w ten sposób działaniu nawet nowego ln). Tymczasowe nazwy plików są łatwe do wykrycia w ls -acelu późniejszego wyczyszczenia w razie potrzeby.
Pan Fooz,
Na marginesie, ja poważnie nie pamiętam, dlaczego nie wystarczy użyć abstarget=$(readlink -f "$link")zamiast przypadku bloku, ale może to być powody przenośności.
grawity
17
Może być łatwiej po prostu użyć tar do skopiowania danych do nowego katalogu.
-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.
Możesz użyć czegoś takiego
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
Podoba mi się twoje rozwiązanie, ale nie rozumiem ostatniej części twojego przesłania. Dla mnie powinieneś zrobić:tar -hcf - sourcedir | tar -xf - -C newdir
Seb DA ROCHA
1
Zgadzam się, ta odpowiedź będzie wymagać aktualizacji zgodnie z komentarzem.
astabada
1
cp -Ljest prostsze rozwiązanie
plesiv
@plesiv true i zgodny z POSIX-em, ale nie wszystkie cpimplementacje skopiują katalogi.
Wyatt8740,
16
Jeśli dobrze cię zrozumiałem, -Lflaga cppolecenia powinna robić dokładnie to, co chcesz.
Po prostu skopiuj wszystkie dowiązania symboliczne, a zastąpi je plikami, na które wskazują.
Dzięki - prawie to, czego potrzebowałem: musiałem zrobić coś takiego: cp -L files tmp/ && rm files && cp tmp/files . jeśli wyjaśnisz, prawdopodobnie pomożesz większej liczbie osób ...
mędrzec
5
najprawdopodobniej będzie to „łatwe”.
Prawdopodobnie napisałbym skrypt, który korzysta z narzędzia wiersza polecenia „znajdź”, aby znaleźć symbolicznie połączone pliki, a następnie wywołuje polecenia rm i cp w celu usunięcia i zastąpienia pliku. Prawdopodobnie dobrze by było, aby akcja została również wywołana przez find sprawdź, czy pozostało wystarczającej ilości wolnego miejsca przed przeniesieniem również łącza sym.
Innym rozwiązaniem może być zamontowanie omawianego systemu plików przez coś, co ukrywa łącza sym (jak samba), a następnie po prostu skopiuj wszystko z tego. Ale w wielu przypadkach coś takiego wprowadzałoby inne problemy.
Bardziej bezpośrednia odpowiedź na twoje pytanie to prawdopodobnie „tak”.
Edycja: zgodnie z prośbą o bardziej szczegółowe informacje. Według strony man dla find , to polecenie wyświetli wszystkie pliki dowiązań sym do głębokości 2 katalogów, z /:
find /-maxdepth 2-type l -exec ./ReplaceSymLink.sh {} \;
Wierzę, że wywoła jakiś skrypt, który właśnie wymyśliłem, i przekazuje nazwę pliku, który właśnie znalazłeś. Alternatywnie, możesz przechwycić wyjście find do pliku (użyj „find [blah]> symlinks.data”, itp.), A następnie przekazać ten plik do skryptu, który napisałeś, aby z wdziękiem poradzić sobie z kopiowaniem oryginału.
Składnia jest następująca-exec ./ReplaceSymLink.sh {} \;
grawity
To jest, aby znaleźć elementy, a ten oznaczony jako odpowiedź służy do zastąpienia linków!
Marty Trenouth
3
Oto oneliner, którego użyłem: załóżmy, że wszystkie pliki lokalne są linkami do innego pliku w „źródle”. Możesz zawęzić wybór plików za pomocą wzorów lub „znaleźć”. Proszę zrozumieć przed użyciem.
dla f w *; do cp --remove-destination source / $ f $ f; gotowy
co powiesz na użycie readlink: for f in *; do cp ---- remove-destination "$ (readlink $ f)" "$ f"; zrobione
Diego
Tak, to dobry pomysł, ale tracisz kontrolę nad operacją. Jednym z ograniczeń mojego rozwiązania jest to, że nie działa ono w przypadku plików ze spacjami w środku lub w przypadku bardzo długich list. Prawdopodobnie ostatecznym rozwiązaniem jest połączenie powyższego „find --exec” z „remove destination”. Czy ktoś chce spróbować?
MastroGeppetto
puste pola pośrodku należy złagodzić, umieszczając „$ f” w podwójnych cudzysłowach. Oto jak używam go z „find & xargs” zamiast „for loop”: find ./ -type l -print0 | xargs -0 -n1 -i sh -c 'cp --remove-destination $ (readlink "{ } ")" {} "'Zamieściłem go jako osobną odpowiedź na widoczność. superuser.com/a/1329543/499386
Diego
2
find .-type l -exec cp --dereference --recursive '{}''{}'.dereferenced \;
Zrobi kopię każdego pliku / folderu z dowiązaniem symbolicznym <filename>.dereferenced, co jest bezpieczniejsze (jeśli mniej wygodne) niż zwykłe zastąpienie ich bezpośrednio. Przeniesienie skopiowanych danych do nazw plików dowiązań symbolicznych pozostawia się jako ćwiczenie dla czytelnika.
Trochę ulepszenia pomoże znaleźć dowiązania symboliczne: dla lnk w `find. -typ l`; do src = $ (readlink $ lnk) && rm $ lnk && mv $ src $ lnk; gotowe (nie testowane hierarchicznie, uważaj jednak na backtyki)
Roman Susi
1
Miałem ten sam problem z kopiowaniem linków przez gwenview, kiedy normalnie spodziewałbyś się, że podąży za linkiem i skopiuje plik.
To, co zrobiłem, aby „wyczyścić” katalog, wykonując wszystkie łącza i kopiując wszystkie wskazane pliki do katalogu, to utworzenie katalogu scratch, uruchom np.
"for file in `ls`; do cp -L $file scratchdir/$file; done; mv scratchdir/* ./"
jest to zbyt niebezpieczne, aby umieścić w skrypcie, ponieważ nie ma sprawdzania, ale naprawiło mój problem.
Odpowiedzi:
W przypadku niektórych definicji „łatwego”:
Uruchom ten skrypt z nazwami łączy jako argumentami, np. Poprzez
find . -type l -exec /path/tos/script {} +
źródło
"$var"
na"${var}"
to noop w sh / bash. Usunąłem jeden bashism ([[
), reszta jest kompatybilna z POSIX sh.cp
utworzenie pliku tymczasowego w tym samym katalogu, a następniemv -f
pliku tymczasowego do oryginału. Powinno to zabezpieczyć się przed problemami takimi jak przytrzymywanie się ludziCtrl-C
lub zapełnianie się systemu plików między poleceniamirm
icp
(zapobiegając w ten sposób działaniu nawet nowegoln
). Tymczasowe nazwy plików są łatwe do wykrycia wls -a
celu późniejszego wyczyszczenia w razie potrzeby.abstarget=$(readlink -f "$link")
zamiast przypadku bloku, ale może to być powody przenośności.Może być łatwiej po prostu użyć tar do skopiowania danych do nowego katalogu.
Możesz użyć czegoś takiego
źródło
tar -hcf - sourcedir | tar -xf - -C newdir
cp -L
jest prostsze rozwiązaniecp
implementacje skopiują katalogi.Jeśli dobrze cię zrozumiałem,
-L
flagacp
polecenia powinna robić dokładnie to, co chcesz.Po prostu skopiuj wszystkie dowiązania symboliczne, a zastąpi je plikami, na które wskazują.
źródło
cp -L files tmp/ && rm files && cp tmp/files .
jeśli wyjaśnisz, prawdopodobnie pomożesz większej liczbie osób ...najprawdopodobniej będzie to „łatwe”.
Prawdopodobnie napisałbym skrypt, który korzysta z narzędzia wiersza polecenia „znajdź”, aby znaleźć symbolicznie połączone pliki, a następnie wywołuje polecenia rm i cp w celu usunięcia i zastąpienia pliku. Prawdopodobnie dobrze by było, aby akcja została również wywołana przez find sprawdź, czy pozostało wystarczającej ilości wolnego miejsca przed przeniesieniem również łącza sym.
Innym rozwiązaniem może być zamontowanie omawianego systemu plików przez coś, co ukrywa łącza sym (jak samba), a następnie po prostu skopiuj wszystko z tego. Ale w wielu przypadkach coś takiego wprowadzałoby inne problemy.
Bardziej bezpośrednia odpowiedź na twoje pytanie to prawdopodobnie „tak”.
Edycja: zgodnie z prośbą o bardziej szczegółowe informacje. Według strony man dla find , to polecenie wyświetli wszystkie pliki dowiązań sym do głębokości 2 katalogów, z /:
( znaleziono to tutaj )
Aby znaleźć, aby wykonać coś po znalezieniu:
Wierzę, że wywoła jakiś skrypt, który właśnie wymyśliłem, i przekazuje nazwę pliku, który właśnie znalazłeś. Alternatywnie, możesz przechwycić wyjście find do pliku (użyj „find [blah]> symlinks.data”, itp.), A następnie przekazać ten plik do skryptu, który napisałeś, aby z wdziękiem poradzić sobie z kopiowaniem oryginału.
źródło
-exec ./ReplaceSymLink.sh {} \;
Oto oneliner, którego użyłem: załóżmy, że wszystkie pliki lokalne są linkami do innego pliku w „źródle”. Możesz zawęzić wybór plików za pomocą wzorów lub „znaleźć”. Proszę zrozumieć przed użyciem.
Mam nadzieję że to pomoże
źródło
Zrobi kopię każdego pliku / folderu z dowiązaniem symbolicznym
<filename>.dereferenced
, co jest bezpieczniejsze (jeśli mniej wygodne) niż zwykłe zastąpienie ich bezpośrednio. Przeniesienie skopiowanych danych do nazw plików dowiązań symbolicznych pozostawia się jako ćwiczenie dla czytelnika.źródło
Korzystając z niektórych wcześniejszych pomysłów, następujące polecenie rekurencyjnie zastąpi każde dowiązanie symboliczne kopią oryginału:
źródło
na podstawie /superuser//a/1301199/499386 of MastroGeppetto
źródło
Jest tam wiele dobrych odpowiedzi, ale odkąd szukałeś czegoś łatwego
źródło
Miałem ten sam problem z kopiowaniem linków przez gwenview, kiedy normalnie spodziewałbyś się, że podąży za linkiem i skopiuje plik.
To, co zrobiłem, aby „wyczyścić” katalog, wykonując wszystkie łącza i kopiując wszystkie wskazane pliki do katalogu, to utworzenie katalogu scratch, uruchom np.
jest to zbyt niebezpieczne, aby umieścić w skrypcie, ponieważ nie ma sprawdzania, ale naprawiło mój problem.
źródło
źródło
Zrobiłem wersję jednowierszową, ponieważ mój hotel nie zezwalał na skrypty bash i działało to dla mnie dobrze:
źródło