Czy istnieje prosty sposób na zastąpienie wszystkich dowiązań symbolicznych plikiem, do którego prowadzą?
Czy istnieje prosty sposób na zastąpienie wszystkich dowiązań symbolicznych plikiem, do którego prowadzą?
Odpowiedzi:
W przypadku niektórych definicji „łatwego”:
#!/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
Uruchom ten skrypt z nazwami łączy jako argumentami, np. Poprzez find . -type l -exec /path/tos/script {} +
"$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ępnie mv -f
pliku tymczasowego do oryginału. Powinno to zabezpieczyć się przed problemami takimi jak przytrzymywanie się ludzi Ctrl-C
lub zapełnianie się systemu plików między poleceniami rm
i cp
(zapobiegając w ten sposób działaniu nawet nowego ln
). Tymczasowe nazwy plików są łatwe do wykrycia w ls -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.
-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
tar -hcf - sourcedir | tar -xf - -C newdir
cp -L
jest prostsze rozwiązanie
cp
implementacje skopiują katalogi.
Jeśli dobrze cię zrozumiałem, -L
flaga cp
polecenia powinna robić dokładnie to, co chcesz.
Po prostu skopiuj wszystkie dowiązania symboliczne, a zastąpi je plikami, na które wskazują.
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 /:
find / -maxdepth 2 -type l -print
Aby znaleźć, aby wykonać coś po znalezieniu:
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.
-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.
dla f w *; do cp --remove-destination source / $ f $ f; gotowy
Mam nadzieję że to pomoże
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.
find ./ -type l -print0|xargs -0 -n1 -i sh -c 'cp --remove-destination $(readlink "{}") "{}" '
na podstawie /superuser//a/1301199/499386 of MastroGeppetto
Jest tam wiele dobrych odpowiedzi, ale odkąd szukałeś czegoś łatwego
for i in *; do link=$(readlink $i) && rm $i && mv $link $i; done
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.
for f in *; do cp --remove-destination $(readlink "$f") "$f"; done
Zrobiłem wersję jednowierszową, ponieważ mój hotel nie zezwalał na skrypty bash i działało to dla mnie dobrze:
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