Bagaimana cara menambahkan beberapa baris di akhir file hanya jika belum ada?


10

Saya ingin mengedit file di tempat dengan menambahkan baris, hanya jika belum ada untuk membuat script saya anti peluru.

Biasanya saya akan melakukan sesuatu seperti:

cat >> ~/.bashrc <<EOF
export PATH=~/.composer/vendor/bin:\$PATH
EOF

Dimungkinkan juga untuk melakukannya via ansible ( line+ insertafter=EOF+ regexp), tapi ini cerita lain.

Dalam vi / ex saya bisa melakukan sesuatu seperti:

ex +'$s@$@\rexport PATH=\~/.composer/vendor/bin:$PATH@' -cwq ~/.bashrc

tetapi kemudian bagaimana saya memeriksa apakah saluran sudah ada (dan dengan demikian tidak melakukan apa-apa) idealnya tanpa mengulangi baris yang sama?

Atau mungkin ada beberapa cara yang lebih mudah untuk melakukannya di Ex editor?


Tidak bisakah Anda melakukan outsourcing? grep -Fq 'export PATH=~/.composer/vendor/bin:$PATH' ~/.bashrc || ex ...(atau cat, dalam hal ini)?
muru

Saya percaya ini bisa menjadi sesuatu yang mirip dengan pendekatan ini , tetapi berlawanan (ketika string tidak ada, lakukan sesuatu).
kenorb

ex ~/.bashrc -c "if search('export PATH=\~\/.composer\/vendor\/bin:\$PATH')>0 | norm quit | endif | norm Aexport PATH=~/.composer/vendor/bin:$PATH"
Alex Kroll

1
Perhatikan itu exportadalah perintah , jadi sisa baris adalah kata shell, BUKAN tugas. Karena itu tidak seperti dengan penugasan variabel (yang tidak digunakan export), Anda perlu tanda kutip ganda atau itu akan pecah di spasi putih . Juga lihat Cara menambahkan jalur ke PATH dengan benar .
Wildcard

1
Saya menemukan tautan yang sebenarnya saya cari kemarin (meskipun tautan di atas juga bagus). Apakah kutipan diperlukan untuk penugasan variabel lokal?
Wildcard

Jawaban:


6

Jika Anda ingin anti peluru , Anda mungkin menginginkan sesuatu yang sedikit lebih portabel daripada opsi rumit di atas. Saya akan tetap berpegang pada fitur POSIXex dan membuatnya bodoh-sederhana: Cukup hapus baris jika ada (terlepas berapa kali itu ada), tambahkan ke akhir file, lalu simpan dan keluar:

ex -sc 'g/^export PATH=\~\/\.composer\/vendor\/bin:\$PATH$/d
$a
export PATH=~/.composer/vendor/bin:$PATH
.
x' ~/.bashrc

Saya berlabuh regex untuk menambah ketahanan, meskipun saya pikir hampir tidak mungkin untuk secara tidak sengaja cocok dengan regex ini. (Berlabuh berarti menggunakan ^dan $regex hanya akan cocok jika cocok dengan seluruh baris.)

Perhatikan bahwa +cmdsintaksis tidak diperlukan oleh POSIX, juga fitur umum yang memungkinkan beberapa -cargumen.


Ada banyak cara sederhana lainnya untuk melakukan ini. Misalnya, tambahkan baris ke akhir file, lalu jalankan dua baris terakhir file melalui filter UNIX eksternal uniq:

ex -sc '$a
export PATH=~/.composer/vendor/bin:$PATH
.
$-,$!uniq
x' input

Ini sangat sangat bersih dan sederhana, dan juga sepenuhnya kompatibel dengan POSIX. Ini menggunakan fitur Escapeex untuk penyaringan teks eksternal, dan utilitas shell yang ditentukan POSIXuniq

Intinya adalah, exini dirancang untuk mengedit file di tempat dan itu adalah jauh cara yang paling portabel untuk mencapai itu secara non-interaktif. Itu bahkan sudah ada sebelum aslinya vi, sebenarnya — nama viitu untuk "editor visual", dan editor non-visual yang digunakannya adalah ex .)


Untuk kesederhanaan yang lebih besar (dan untuk menguranginya menjadi satu baris), gunakan printfuntuk mengirim perintah ke ex:

printf %s\\n '$a' 'export PATH=~/.composer/vendor/bin:$PATH' . '$-,$!uniq' x | ex input


2

Solusi yang mungkin adalah membuat fungsi untuk melakukan itu:

function! AddLine()

    let l:res = 0
    g/export PATH=\~\/.composer\/vendor\/bin:\\\$PATH/let l:res = l:res+1

    if (l:res == 0)
        normal G
        normal oexport PATH=~/.composer/vendor/bin:\$PATH
    endif

endfunction

Pertama kita membuat variabel lokal l:resyang akan digunakan untuk menghitung jumlah kemunculan baris.

Kami menggunakan globalperintah: setiap kali garis dicocokkan, l:resbertambah.

Akhirnya jika l:resmasih 0 itu berarti bahwa baris tersebut tidak muncul dalam file jadi kami pergi ke baris terakhir terima kasih G, dan kami membuat baris baru oyang dengannya kami menulis baris untuk ditambahkan.

Catatan 1 Metode yang saya gunakan untuk mengatur nilai l:ressedikit berat dan dapat diganti dengan yang disarankan oleh @Alex dalam jawabannya dengan sesuatu seperti:

let l:res = search('export PATH=\~\/.composer\/vendor\/bin:\\\$PATH')

Catatan 2 Juga untuk membuat fungsi lebih fleksibel Anda bisa menggunakan argumen:

function! AddLine(line)

    let l:line =  escape(a:line, "/~$" )

    let l:res = 0
    exe "g/" . l:line . "/let l:res = l:res+1"

    if (l:res == 0)
        normal G
        exe "normal o" . a:line
    endif

endfunction
  • Perhatikan trik dengan escape()menambahkan \di depan karakter yang dapat menyebabkan masalah dalam pencarian.
  • Perhatikan juga bahwa Anda masih harus keluar \sendiri saat memanggil fungsi (saya tidak berhasil melarikan diri \secara otomatis):

    call AddLine("export PATH=~/.composer/vendor/bin:\\$PATH")
    

2

Mencoba:

ex ~/.bashrc -c "if search('export PATH=\~\/.composer\/vendor\/bin:\$PATH')>0 | norm quit | endif | norm Aexport PATH=~/.composer/vendor/bin:$PATH"

Catatan yang :appendtidak akan berfungsi di dalam if endif-block dengan mode Ex (lihat VimDoc ) jadi saya harus meletakkan di norm A...luar.


1

Saya biasanya menggunakan:

perl -i -p0e '$_.="export PATH=~/bin:\$PATH\n" unless m!~/bin:!' ~/.bashrc

1

Untuk menyederhanakan dan menghindari kehadiran banyak orang \, baris yang akan ditambahkan adalah export PATH=mybin:PATH.

Strategi utama: gantikan mybinteks " non- " (semua file) dengan teks + mybin-path-definition:

 vim  +'s#\v%^((.|\n)(mybin:)@!)*%$#&\rexport PATH=mybin:PATH#e' -cx bashrc

atau dengan lekukan yang lebih didaktik :

s#                                    substitute
   \v                                  very magical to redude \

   %^                                  file begin
   ((.|\n)(mybin:)@!)*                 multi-line str without "mybin:"
                                         (any char not followed by "mybin")*
   %$                                  end of file
 #                                    by

Jika kami memiliki kecocokan:

  1. &memiliki teks lengkap bashrcdan
  2. & tidak mengandung /mybin:/

begitu:

 #                                    by ...
   &                                   all file
   export PATH=mybin:PATH              and the new path
 #e                                   don't complain if patt not found

-cx                                   save and leave 

PEMBARUAN : Akhirnya, kita dapat membuat skrip vim:

$ cat bashrcfix

#!/usr/bin/vim -s
:e ~/fakebashrc
:s#\v%^((.|\n)(mybin:)@!)*%$#&\rexport PATH=mybin:PATH#e
:x

chmod 755 dan instal. Pemakaian:bashrcfix


hati-hati: dalam \vmode, =berarti opsional


1

Sebagian besar dari jawaban ini tampaknya rumit bagaimana dengan perintah shell lama yang baik:

grep composer/vender ~/.bashrc || cat >> ~/.bashrc <<EOF
export PATH=~/.composer/vendor/bin:\$PATH
EOF

Ini bisa dengan mudah menjadi fungsi Bash:

addBashrcPath() {
  if ! grep "$1" ~/.bashrc >/dev/null 2>&1; then
    printf 'export PATH=%s:$PATH' "$1" >> ~/.bashrc
  fi
}

addBashrcPath "~/.composer/vendor/bin"

EDIT : Kode keluar grep penting dan dalam hal ini perlu dibalik penggunaannya ! grep; grep -vtidak akan keluar seperti yang diharapkan dalam situasi ini. Terima kasih @joeytwiddle atas tipnya.


Saya tidak berpikir grep -vmemberi Anda kode keluar yang Anda inginkan. Tetapi ! grepharus melakukannya.
joeytwiddle

Jika itu masalahnya maka Anda bahkan tidak perlu -vhanya !.
Sukima

Persis. Anda dapat mengedit jawaban Anda untuk melakukan koreksi itu.
joeytwiddle

1
1. Anda harus menggunakan -Fsehingga grepdosnot menafsirkan karakter sebagai ekspresi reguler, dan 2. Gunakan -qalih-alih mengarahkan /dev/null. Lihat komentar saya sebelumnya pada pertanyaan .
muru

Poin bagus. Ingin tahu seberapa portabel -qdan -Fopsi? Saya pikir >/dev/nullitu lebih universal di antara platform yang berbeda (sun vs hp vs Mac OS X vs Ubuntu vs FreeBSD vs ...)
Sukima
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.