Menambahkan baris ke file hanya jika belum ada


157

Saya perlu menambahkan baris berikut ke akhir file konfigurasi:

include "/configs/projectname.conf"

ke file yang disebut lighttpd.conf

Saya melihat kegunaan seduntuk melakukan ini, tetapi saya tidak tahu caranya.

Bagaimana saya hanya memasukkannya jika salurannya belum ada?


Jika Anda mencoba mengedit file-in, alat ini crudinimungkin merupakan opsi yang baik (tetapi belum untuk lighthttpd)
rubo77

Jawaban:


292

Sederhana saja :)

grep + echo sudah cukup:

grep -qxF 'include "/configs/projectname.conf"' foo.bar || echo 'include "/configs/projectname.conf"' >> foo.bar

Edit: memasukkan @cerin dan saran @ thijs-wouters .


2
Saya akan menambahkan -q beralih ke grep untuk menekan output: grep -vq ...
Dave Kirby

1
FYI, menggunakan -v dan && tidak terlihat berhasil, sedangkan || tanpa -v bekerja.
bPizzi

3
Ini hanya berfungsi untuk garis yang sangat sederhana. Jika tidak, grep menginterpretasikan sebagian besar karakter non-alfa di baris Anda sebagai pola, menyebabkannya tidak mendeteksi baris dalam file.
Cerin

2
Solusi indah. Ini juga berfungsi untuk memicu ekspresi yang lebih rumit, tentu saja. Milik saya menggunakan echountuk memicu catheredoc multiline ke file konfigurasi.
Eric L.

2
Tambah -suntuk mengabaikan kesalahan ketika file tidak ada, membuat file baru hanya dengan baris itu.
Frank

78

Ini akan menjadi solusi yang bersih, mudah dibaca dan dapat digunakan kembali menggunakan grepdan echomenambahkan baris ke file hanya jika belum ada:

LINE='include "/configs/projectname.conf"'
FILE='lighttpd.conf'
grep -qF -- "$LINE" "$FILE" || echo "$LINE" >> "$FILE"

Jika Anda harus mencocokkan penggunaan seluruh baris grep -xqF

Tambah -suntuk mengabaikan kesalahan ketika file tidak ada, membuat file baru hanya dengan baris itu.


5
Jika itu ke file di mana Anda memerlukan izin root:sudo grep -qF "$LINE" "$FILE" || echo "$LINE" | sudo tee -a "$FILE"
nebffa

Ini sebenarnya tidak berfungsi ketika baris dimulai dengan a -.
hyperknot

@ zsero: poin bagus! Saya menambahkan --dalam perintah grep, jadi itu tidak akan menafsirkan $ LINE dimulai dengan tanda hubung sebagai opsi lagi.
rubo77

13

Ini sebuah sedversi:

sed -e '\|include "/configs/projectname.conf"|h; ${x;s/incl//;{g;t};a\' -e 'include "/configs/projectname.conf"' -e '}' file

Jika string Anda dalam variabel:

string='include "/configs/projectname.conf"'
sed -e "\|$string|h; \${x;s|$string||;{g;t};a\\" -e "$string" -e "}" file

Untuk perintah yang menggantikan sebagian string dengan entri file konfigurasi lengkap / yang diperbarui, atau menambahkan baris sesuai kebutuhan:sed -i -e '\|session.*pam_mkhomedir.so|h; ${x;s/mkhomedir//;{g;tF};a\' -e 'session\trequired\tpam_mkhomedir.so umask=0022' -e '};:F;s/.*mkhomedir.*/session\trequired\tpam_mkhomedir.so umask=0022/g;' /etc/pam.d/common-session
bgStack15

Bagus, itu banyak membantu saya memberi +1. bisa tolong jelaskan ekspresimu?
Rahul

Saya ingin melihat penjelasan solusi ini yang beranotasi. Saya sudah menggunakan sedselama bertahun-tahun tetapi kebanyakan hanya sperintah. The holddan patternswap space yang di luar saya.
nortally

11

Jika menulis ke file yang dilindungi, jawaban @drAlberT dan @ rubo77 mungkin tidak berfungsi untuk Anda karena orang tidak dapat melakukan sudo >>. Sebuah solusi sama sederhana , maka, akan menggunakan tee --append(atau, pada MacOS, tee -a):

LINE='include "/configs/projectname.conf"'
FILE=lighttpd.conf
grep -qF "$LINE" "$FILE"  || echo "$LINE" | sudo tee --append "$FILE"

6

Jika, suatu hari, orang lain harus berurusan dengan kode ini sebagai "kode warisan", maka orang itu akan berterima kasih jika Anda menulis kode yang kurang eksoteris, seperti

grep -q -F 'include "/configs/projectname.conf"' lighttpd.conf
if [ $? -ne 0 ]; then
  echo 'include "/configs/projectname.conf"' >> lighttpd.conf
fi

1
Maaf, jika Anda tidak tahu shell, maka pergi dan kelola Windows. Solusi menggunakan && dan || adalah sintaksis shell normal, dan harus dipahami oleh admin yang kompeten. Tidak ada yang esoteris di sana sama sekali.
Graham Nicholls

3
Terima kasih atas komentar Anda, Graham! Ya, itu adalah sintaksis shell normal. Dan ya, setiap admin yang kompeten harus memahaminya. Namun, ia bekerja berdasarkan efek samping dari algoritma evaluasi ekspresi di dalam shell. Jadi Anda bisa menyebutnya sesuka Anda, kecuali langsung - yang merupakan poin awal saya.
Marcelo Ventura


6

solusi sed lain adalah untuk selalu menambahkannya di baris terakhir dan menghapus yang sudah ada sebelumnya.

sed -e '$a\' -e '<your-entry>' -e "/<your-entry-properly-escaped>/d"

"lolos dengan benar" berarti menempatkan regex yang cocok dengan entri Anda, yaitu untuk menghindari semua kontrol regex dari entri Anda yang sebenarnya, yaitu untuk meletakkan backslash di depan ^ $ / *? + ().

ini mungkin gagal pada baris terakhir file Anda atau jika tidak ada baris baru yang menggantung, saya tidak yakin, tapi itu bisa ditangani oleh beberapa percabangan yang bagus ...


1
Bagus satu garis, pendek dan mudah dibaca. Bekerja sangat baik untuk memperbarui dll / host:sed -i.bak -e '$a\' -e "$NEW_IP\t\t$HOST.domain\t$HOST" -e "/.*$HOST/d" /etc/hosts
Noam Manos

Versi yang lebih kecil:sed -i -e '/<entry>/d; $a <entry>'
Jérôme Pouiller

@ Jezz Saya pikir ini akan gagal, jika entri sudah ada di akhir file, karena dperintah akan me-restart program sed dan dengan demikian melewatkan append, jika penghapusan kebetulan berada di baris terakhir.
Robin479

@ Robin479 Damned, append harus dilaksanakan sebelum dapus: sed -i -e '$a<entry>' -e '/<entry>/d'. Itu hampir sama dengan jawaban awal Anda.
Jérôme Pouiller

3

gunakan awk

awk 'FNR==NR && /configs.*projectname\.conf/{f=1;next}f==0;END{ if(!f) { print "your line"}} ' file file

Apakah ini 'file file' atau hanya 'file'?
webdevguy

Itu file filekarena membuat dua melewati file yang sama. NR==FNRbenar pada pass pertama, tetapi tidak pada pass kedua. Ini adalah ungkapan awk yang umum.
tripleee

1

Jawaban menggunakan grep salah. Anda perlu menambahkan opsi -x untuk mencocokkan seluruh baris jika tidak, baris seperti #text to addmasih akan cocok ketika ingin menambahkan dengan tepat text to add.

Jadi solusi yang benar adalah sesuatu seperti:

grep -qxF 'include "/configs/projectname.conf"' foo.bar || echo 'include "/configs/projectname.conf"' >> foo.bar

1

Menggunakan sed: Ini akan menyisipkan di akhir baris. Anda juga dapat mengirimkan variabel seperti biasa.

grep -qxF "port=9033" $light.conf
if [ $? -ne 0 ]; then
  sed -i "$ a port=9033" $light.conf
else
    echo "port=9033 already added"
fi

Menggunakan oneliner sed

grep -qxF "port=9033" $lightconf || sed -i "$ a port=9033" $lightconf

Menggunakan gema mungkin tidak berfungsi di bawah root, tetapi akan berfungsi seperti ini. Tapi itu tidak akan membiarkan Anda mengotomatiskan hal-hal jika Anda ingin melakukannya karena mungkin meminta kata sandi.

Saya punya masalah ketika saya mencoba mengedit dari root untuk pengguna tertentu. Hanya menambahkan $usernamesebelumnya adalah perbaikan untuk saya.

grep -qxF "port=9033" light.conf
if [ $? -ne 0 ]; then
  sudo -u $user_name echo "port=9033" >> light.conf
else
    echo "already there"    
fi

Selamat datang di stackoverflow! Silakan baca pertanyaan dengan seksama sebelum mengirim jawaban - OP bertanya bagaimana memasukkan menggunakan sed
Markoorn

-1

Saya perlu mengedit file dengan izin tulis terbatas sehingga diperlukan sudo. bekerja dari jawaban ghostdog74 dan menggunakan file temp:

awk 'FNR==NR && /configs.*projectname\.conf/{f=1;next}f==0;END{ if(!f) { print "your line"}} ' file > /tmp/file
sudo mv /tmp/file file

Ini tidak terlihat benar, itu akan kehilangan baris lain dari file ketika baris konfigurasi hilang.
tripleee
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.