Saya sedang menulis skrip shell untuk server saya, yang merupakan hosting bersama yang menjalankan FreeBSD. Saya juga ingin dapat mengujinya secara lokal, di PC saya yang menjalankan Linux. Oleh karena itu, saya mencoba menulisnya dengan cara yang portabel, tetapi dengan sed
saya tidak melihat cara untuk melakukannya.
Bagian dari situs web saya menggunakan file HTML statis yang dihasilkan, dan baris sed ini menyisipkan DOCTYPE yang benar setelah setiap regenerasi:
sed -i '1s/^/<!DOCTYPE html> \n/' ${file_name.html}
Ini bekerja dengan GNU sed
di Linux, tetapi FreeBSD sed
mengharapkan argumen pertama setelah -i
opsi menjadi ekstensi untuk salinan cadangan. Ini akan terlihat seperti:
sed -i '' '1s/^/<!DOCTYPE html> \n/' ${file_name.html}
Namun, GNU sed
pada gilirannya mengharapkan ekspresi mengikuti segera setelahnya -i
. (Ini juga membutuhkan perbaikan dengan penanganan baris baru, tapi itu sudah dijawab di sini )
Tentu saja saya dapat memasukkan perubahan ini dalam salinan server saya dari skrip, tetapi itu akan mengacaukan yaitu penggunaan VCS untuk versi. Apakah ada cara untuk mencapai ini dengan sed dalam cara yang sepenuhnya portabel?
-i
Jawaban:
GNU sed menerima ekstensi opsional setelahnya
-i
. Perpanjangan harus dalam argumen yang sama tanpa ruang intervensi. Sintaks ini juga berfungsi pada BSD sed.Perhatikan bahwa pada BSD,
-i
juga mengubah perilaku ketika ada beberapa file input: mereka diproses secara independen (jadi misalnya$
cocok dengan baris terakhir dari setiap file). Juga ini tidak akan berfungsi pada BusyBox.Jika Anda tidak ingin menggunakan file cadangan, Anda dapat memeriksa versi sed yang tersedia.
Atau sebagai alternatif, untuk menghindari mengacaukan parameter posisi, tentukan fungsi.
Jika Anda tidak ingin repot, gunakan Perl.
Jika Anda ingin menulis skrip portabel, jangan gunakan
-i
- ini bukan di POSIX. Lakukan secara manual apa yang dilakukan sed di bawah tenda - itu hanya satu baris kode lagi.sumber
sed -i
juga menyiratkan-s
. Dan cara termudah untuk memeriksa GNUsed
adalah dengansed v
perintah yang merupakan noop sah untuk GNU tetapi gagal di tempat lain.sed -i$(sed v < /dev/null 2> /dev/null || echo -n " ''") -e '...' "$file"
Jika bukan GNU sed, ia menyisipkan spasi diikuti oleh dua tanda kutip setelah-i
sehingga bekerja pada BSD. GNU sed hanya mendapat-i
.v
perintah untuk menguji GNU sed. Bagaimana jika FreeBSD memutuskan untuk mengimplementasikannya?sed v
karena itulah tujuannya untuk tetap ada.Jika Anda tidak menemukan trik untuk menjadikan
sed
permainan menyenangkan, Anda dapat mencoba:Jangan gunakan
-i
:Gunakan Perl
sumber
ed
Anda selalu dapat menggunakan
ed
untuk menambahkan baris ke file yang ada.Detail
Bit di sekitar
<!DOCTYPE html>
adalah perintah untuked
menginstruksikannya untuk menambahkan baris itu ke filemy.html
.sed
Saya percaya perintah
sed
ini juga dapat digunakan:sumber
Anda juga dapat melakukan secara manual apa yang
perl -i
ada di bawah tenda:Seperti
perl -i
, tidak ada cadangan, dan seperti kebanyakan solusi yang diberikan di sini, berhati-hatilah itu dapat memengaruhi izin, kepemilikan file, dan dapat mengubah symlink menjadi file biasa.Dengan:
sed
akan menimpa file itu sendiri, sehingga tidak akan memengaruhi kepemilikan dan izin atau symlink. Ini berfungsi dengan GNUsed
karenased
biasanya akan membaca buffer penuh data darifile
(4k dalam kasus saya) sebelum menimpa dengani
perintah. Itu tidak akan berhasil jika file lebih dari 4k kecuali untuk fakta yangsed
juga buffer outputnya.Pada dasarnya
sed
bekerja pada balok 4k untuk membaca dan menulis. Jika jalur untuk memasukkan lebih kecil dari 4k,sed
tidak akan pernah menimpa blok yang belum dibaca.Saya tidak akan mengandalkan itu.
sumber
echo '<!DOCTYPE html>'
atau melarikan diri tanpa "" kutipan.FreeBSD sed , yang digunakan pada Mac OS X juga, membutuhkan
-e
opsi setelah-i
saklar untuk mendefinisikan & mengenali perintah (regex) berikut dengan benar & jelas.Dengan kata lain,
sed -i -e ...
harus bekerja dengan FreeBSD & GNUsed
.Secara lebih umum, menghilangkan ekstensi cadangan setelah FreeBSD
sed -i
memerlukan beberapased
opsi eksplisit atau beralih mengikuti-i
untuk menghindari kebingungan pada bagian FreeBSDsed
sambil mem-parsing argumen command-line-nya.(Namun, perhatikan bahwa
sed
pengeditan file di tempat menyebabkan perubahan inode file, lihat "Di tempat" mengedit file ).(Sebagai petunjuk umum, FreeBSD versi terbaru
sed
memiliki-r
saklar untuk meningkatkan kompatibilitas dengan GNUsed
).sumber
bsdsed -i -e 's/a/A/'
ini bukan di tempat editing, itu mengedit dengan tabungan asli dengan "-e" akhiran (testfile.txt-e
).Untuk meniru
sed -i
untuk satu file dengan mudah sambil menghindari kondisi balapan sebanyak mungkin:Omong-omong, ini juga menangani masalah yang mungkin muncul di dalamnya
sed -i
, tergantung pada izin direktori dan file,sed -i
mungkin memungkinkan pengguna untuk menimpa file yang pengguna tidak memiliki izin untuk mengedit.Anda juga dapat melakukan pencadangan seperti:
sumber
Anda dapat menggunakan Vim dalam mode Ex:
1
pilih baris pertamai
masukkan teks dan baris barux
Simpan dan tutupAtau bahkan, seperti dalam komentar, standar
ex
lama :sumber
ex
, kecuali bahwa implementasi tidak diperlukan untuk mendukung banyak-c
flag. Untuk portabilitas yang pasti saya akan gunakanprintf '%s\n' 1i '<!DOCTYPE html>' . x | ex file