Ganti Tautan Simbolik dengan File


31

Apakah ada cara mudah untuk mengganti semua tautan simbolik dengan file yang ditautkannya?


3
Masalah apa yang sedang ingin kamu selesaikan?
Daniel Beck

3
Saya memiliki banyak tautan simbolik ke drive lain. Saya perlu memindahkan semua file dari drive yang dirujuk di tempat lain sehingga saya dapat menghapusnya.
Marty Trenouth

Jawaban:


14

Untuk beberapa definisi "mudah":

#!/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

Jalankan skrip ini dengan nama tautan sebagai argumen, misalnya melalui find . -type l -exec /path/tos/script {} +


2
Terima kasih untuk mengedit, anon, tapi script tidak menangani nama file dengan spasi baik-baik saja, dengan mengutip variabel di semua tempat yang diperlukan. Mengubah "$var"ke "${var}"adalah noop di sh / bash. Saya menghapus satu bashism ( [[), sisanya kompatibel dengan POSIX sh.
grawity

Metode yang bahkan lebih kuat untuk menangani kegagalan symlink adalah cpdengan membuat file sementara di direktori yang sama kemudian mv -ffile sementara itu menjadi yang asli. Ini harus melindungi dari masalah seperti orang yang menahan Ctrl-Catau sistem file yang mengisi antara perintah rmdan cp(sehingga mencegah bahkan yang baru lnbekerja). Nama file sementara mudah dikenali ls -auntuk pembersihan nanti jika diperlukan.
Tuan Fooz

Sebagai catatan tambahan, saya benar-benar tidak dapat mengingat mengapa saya tidak hanya menggunakan abstarget=$(readlink -f "$link")bukan case case , tetapi itu mungkin merupakan alasan portabilitas.
grawity

17

Mungkin lebih mudah menggunakan tar untuk menyalin data ke direktori baru.

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

Anda bisa menggunakan sesuatu seperti ini

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

1
Saya suka solusi Anda, tetapi saya tidak mengerti bagian terakhir dari pesan Anda. Bagi saya, Anda harus melakukan:tar -hcf - sourcedir | tar -xf - -C newdir
Seb DA ROCHA

1
Setuju, jawaban ini perlu diperbarui sesuai komentar.
astabada

1
cp -Ladalah solusi yang lebih sederhana
plesiv

@plesiv true, dan posix-compliant, tetapi tidak semua cpimplementasi akan menyalin direktori.
Wyatt8740

16

Jika saya mengerti Anda dengan benar -Lbendera cpperintah harus melakukan apa yang Anda inginkan.

Cukup salin semua symlink dan itu akan menggantinya dengan file yang mereka tuju.


4
Terima kasih - hampir apa yang saya butuhkan: Saya harus melakukan sesuatu seperti: cp -L files tmp/ && rm files && cp tmp/files . Jika Anda mengklarifikasi, Anda mungkin akan membantu lebih banyak orang ...
bijak

5

"Mudah" akan menjadi fungsi Anda, kemungkinan besar.

Saya mungkin akan menulis skrip yang menggunakan utilitas baris perintah "find" untuk menemukan file yang terhubung secara simbolis, kemudian memanggil rm dan cp untuk menghapus dan mengganti file. Anda mungkin sebaiknya melakukan tindakan yang disebut dengan find check bahwa ada ruang kosong yang tersisa sebelum memindahkan tautan sym juga.

Solusi lain mungkin dengan me-mount sistem file yang dimaksud melalui sesuatu yang menyembunyikan tautan sym (seperti samba), lalu salin semuanya dari itu. Tetapi dalam banyak kasus, sesuatu seperti itu akan menimbulkan masalah lain.

Jawaban yang lebih langsung untuk pertanyaan Anda mungkin "ya".

Sunting: Sesuai permintaan untuk info yang lebih spesifik. Menurut halaman manual untuk find , perintah ini akan mencantumkan semua file tautan sym ke kedalaman 2 direktori, dari /:

find / -maxdepth 2 -type l -print

( ini ditemukan di sini )

Untuk mendapatkan temukan untuk mengeksekusi sesuatu pada menemukannya:

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

Saya yakin itu akan memanggil beberapa script yang baru saja saya buat, dan meneruskan nama file yang baru saja Anda temukan. Sebagai alternatif, Anda dapat menangkap output find ke file (gunakan "find [blah]> symlinks.data", dll) lalu berikan file itu ke skrip yang Anda tulis untuk menangani penyalinan di atas dokumen asli dengan anggun.


? Agak generik - bisakah Anda menguraikan?
Linker3000

2
Sintaksnya adalah-exec ./ReplaceSymLink.sh {} \;
grawity

Ini untuk mencari item dan yang ditandai sebagai jawaban digunakan untuk mengganti tautan!
Marty Trenouth

3

Ini adalah oneliner yang saya gunakan: menganggap semua file lokal adalah tautan ke file lain di "sumber". Anda dapat memperbaiki pemilihan file dengan pola atau "menemukan". Tolong, mengerti sebelum menggunakan.

untuk f di *; do cp --hapus sumber tujuan / $ f $ f; selesai

Semoga ini membantu


bagaimana menggunakan readlink: for f in *; jangan cp ---- hapus-tujuan "$ (readlink $ f)" "$ f"; selesai
Diego

Ya, itu ide yang bagus, tetapi Anda kehilangan kontrol pada operasi. Salah satu batasan dari solusi saya adalah tidak berfungsi untuk file yang kosong di tengah, atau untuk daftar yang sangat panjang. Mungkin solusi terakhir adalah menyatukan 'find --exec' di atas dengan 'remove destination'. Adakah yang mau mencoba?
MastroGeppetto

kosong di tengah harus dikurangi dengan menempatkan "$ f" dalam tanda kutip. Inilah cara saya menggunakannya dengan "find & xargs" alih-alih "for loop": find ./ -type l -print0 | xargs -0 -n1 -i sh -c 'cp --hapus-tujuan $ (readlink "{ } ")" {} "'Saya telah mempostingnya sebagai jawaban terpisah untuk visibilitas. superuser.com/a/1329543/499386
Diego

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

Akan membuat salinan dari setiap file / folder yang disinkronkan <filename>.dereferenced, yang lebih aman (jika kurang nyaman) daripada hanya menggantinya secara langsung. Memindahkan data yang disalin ke nama file symlink dibiarkan sebagai latihan untuk pembaca.


2

Menggunakan beberapa ide sebelumnya, perintah berikut akan secara rekursif mengganti setiap symlink dengan salinan aslinya:

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


1

Ada banyak jawaban bagus di sana tetapi saya karena Anda mencari sesuatu yang mudah

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

Sedikit peningkatan akan membantu menemukan tautan simbolik: untuk lnk di `find. -tipe l`; do src = $ (readlink $ lnk) && rm $ lnk && mv $ src $ lnk; selesai (tidak diuji dengan hierarki, hati-hati dengan backticks)
Roman Susi

1

Saya memiliki masalah yang sama dengan tautan gwenview menyalin ketika Anda biasanya mengharapkannya untuk mengikuti tautan dan menyalin file.

Apa yang saya lakukan untuk 'membersihkan' direktori dengan mengikuti semua tautan dan menyalin semua file yang diarahkan ke direktori, adalah membuat direktori awal, jalankan mis.

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

ini terlalu berbahaya untuk dimasukkan ke dalam skrip karena tidak ada pemeriksaan tetapi ini memperbaiki masalah saya.



0

Saya membuat versi satu baris, karena hotel web saya tidak mengizinkan skrip bash dan itu berfungsi dengan baik untuk saya:

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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.