Seorang teman saya menunjukkan bahwa jika Anda melakukannya:
perl -pi.bak -e 's/foo/bar/' somefile
ketika "somefile" sebenarnya adalah symlink, perl melakukan apa yang akan dilakukan dokumen:
Ini dilakukan dengan mengganti nama file input, membuka file output dengan nama asli, dan memilih file output sebagai default untuk pernyataan print (). Ekstensi, jika disediakan, digunakan untuk mengubah nama file lama untuk membuat salinan cadangan [...]
Yang menghasilkan symlink baru "somefile.bak" yang menunjuk ke file nyata yang tidak berubah, dan yang baru, mengubah file biasa "somefile" dengan perubahan.
Dalam banyak kasus, mengikuti symlink akan menjadi perilaku yang diinginkan (bahkan jika itu meninggalkan lokasi yang benar dari file .bak ambigu). Apakah ada cara sederhana untuk melakukan ini selain menguji untuk symlink dalam bungkus dan menangani kasing dengan tepat?
( sed
melakukan hal yang sama, untuk apa nilainya.)
-p -i
dalam skrip Anda.Jawaban:
Saya bertanya-tanya apakah
sponge
utilitas serba guna kecil ("menyerap input standar dan menulis ke file") dari moreutils akan membantu dalam kasus ini dan apakah ia akan mengikuti symlink.Penulis menggambarkan
sponge
seperti ini:sumber
sponge
penggunaannya dalam praktik? Bagi saya: belum. Bisakah Anda meninggalkan komentar yang menyatakan apakah itu berlaku dalam tes seperti yang diinginkan di sini? Oh, saya melihat komentar. Terima kasih atas konfirmasinya!file
dalam contoh Anda di atas adalah symlink, tautan dibiarkan sendiri dan file asli berubah.Jika Anda mengetahui fakta bahwa itu
somefile
adalah symlink, Anda dapat secara eksplisit menyediakan path lengkap ke file dengan yang berikut ini:perl -pi.bak -e 's/foo/bar/' $(readlink somefile)
Dengan begitu, symlink asli tetap utuh karena penggantian sekarang dilakukan langsung dengan file asli.
sumber
readlink
mungkin masih symlink lain. Terbaik akan menggunakan-f
atau-e
di mana tersedia atauzsh
's$file:P
atau(:P)
gumpal kualifikasi seperti yang ditunjukkan oleh @ikegami untuk mendapatkan jalan symlink bebas.Jika Anda berurusan dengan satu file itu, perintahnya akan terlihat sebagai berikut:
Solusinya adalah sebagai berikut:
Ini menangani symlink dan non-symlink.
Jika Anda berurusan dengan sejumlah besar file secara sewenang-wenang, perintahnya akan terlihat sebagai berikut:
Solusinya adalah sebagai berikut:
Ini menangani symlink dan non-symlink.
Peringatan
readlink
bukanlah perintah standar, jadi itu keberadaan, argumennya, dan fungsinya bervariasi menurut sistem, jadi pastikan untuk memeriksa dokumentasi Anda. Sebagai contoh, beberapa implementasi memiliki-f
(yang juga bisa Anda gunakan di sini), tetapi tidak-e
, beberapa tidak.busybox
Inireadlink -f
berperilaku seperti GNUreadlink -e
. Dan beberapa sistem memilikirealpath
perintah alih-alihreadlink
yang umumnya berperilaku seperti GNUreadlink -f
.Berhati-hatilah dengan GNU
readlink -e
, symlink yang tidak dapat diselesaikan ke file yang ada dihapus secara diam-diam.sumber
$var:P
tidak bekerja untuk saya. (X='tmp' zsh -c 'perl -E"say for @ARGV" $X:P'
keluarantmp:P
)$var:P
. Dengan versi yang lebih lama, Anda selalu dapat menggunakannya$var:A
. Lihat manual untuk perbedaan dan zsh.org/mla/users/2016/msg00593.html untuk alasan untuk memperkenalkan:P
(realpath()
antarmuka nyata ).:A
ditambahkan pada 4.3.10 (2009), GNUreadlink -z
pada 2012, saya tidak mengetahui adanyareadlink
implementasi lain yang mendukung-z
). Perhatikan bahwa dengan GNUxargs
, Anda biasanya menginginkan-r
opsi kecuali Anda dapat menjamin input tidak akan kosong. Di sini, ini bukan masalah besar (kecualiperl
kode berisiBEGIN
/END
pernyataan), Anda hanya akan mendapat-i used with no filenames on the command line, reading from STDIN.
peringatan jika itu terjadi.-r
dokumentasi. Saya pikir saya melakukan kebalikan dari apa yang dilakukannya. Siap