Làm thế nào để nối một số dòng ở cuối tập tin chỉ khi nó chưa có?


10

Tôi muốn chỉnh sửa một tập tin tại chỗ bằng cách nối thêm một dòng, chỉ khi chưa tồn tại để làm cho kịch bản của tôi chống đạn.

Thông thường tôi sẽ làm một cái gì đó như:

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

Cũng có thể thực hiện thông qua ansible ( line+ insertafter=EOF+ regexp), nhưng đó là một câu chuyện khác.

Trong vi / ex tôi có thể làm một cái gì đó như:

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

nhưng sau đó làm thế nào để tôi kiểm tra xem dòng đã có ở đó chưa (và do đó không làm gì) một cách lý tưởng mà không lặp lại cùng một dòng?

Hoặc có thể có một số cách dễ dàng hơn để làm điều đó trong trình soạn thảo Ex?


Bạn không thể thuê ngoài nó? grep -Fq 'export PATH=~/.composer/vendor/bin:$PATH' ~/.bashrc || ex ...(hoặc cat, cho vấn đề đó)?
muru

Tôi tin rằng đây có thể là một cái gì đó tương tự như phương pháp này , nhưng ngược lại (khi chuỗi không có ở đó, hãy làm một cái gì đó).
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
Lưu ý rằng đó exportlà một lệnh , vì vậy phần còn lại của dòng là một từ shell, KHÔNG phải là một bài tập. Do đó, không giống như một phép gán biến (không sử dụng export), bạn cần dấu ngoặc kép hoặc nó sẽ bị hỏng trên khoảng trắng . Ngoài ra, hãy xem Cách thêm chính xác đường dẫn đến PATH .
tự đại diện

1
Tôi tìm thấy liên kết thực tế mà tôi đang tìm kiếm ngày hôm qua (mặc dù các liên kết trên cũng tốt). Là trích dẫn cần thiết cho việc gán biến cục bộ?
tự đại diện

Câu trả lời:


6

Nếu bạn muốn chống đạn , có lẽ bạn muốn thứ gì đó dễ mang hơn một chút so với các tùy chọn phức tạp ở trên. Tôi sẽ sử dụng các tính năng POSIX củaex nó và làm cho nó trở nên đơn giản: Chỉ cần xóa dòng nếu nó ở đó (bất kể bao nhiêu lần ở đó), thêm nó vào cuối tệp, sau đó lưu và thoát:

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

Tôi đã gắn kết regex để tăng thêm sự mạnh mẽ, mặc dù tôi nghĩ rằng gần như không thể vô tình phù hợp với regex này. (Neo có nghĩa là sử dụng ^$do đó regex sẽ chỉ khớp nếu nó khớp với toàn bộ một dòng.)

Lưu ý rằng +cmdcú pháp không được POSIX yêu cầu, cũng không phải là tính năng phổ biến của việc cho phép nhiều -cđối số.


Có vô số cách đơn giản khác để làm điều này. Chẳng hạn, thêm dòng vào cuối tệp, sau đó chạy hai dòng cuối của tệp thông qua bộ lọc UNIX bên ngoài uniq:

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

Điều này rất rất sạch sẽ và đơn giản, và cũng hoàn toàn tuân thủ POSIX. Nó sử dụng tính năng Escape củaex để lọc văn bản bên ngoài và tiện ích shell do POSIX chỉ địnhuniq

Điểm mấu chốt là, exđược thiết kế để chỉnh sửa tập tin tại chỗ và cho đến nay, đây là cách di động nhất để thực hiện điều đó theo cách không tương tác. Nó xảy ra trước thậm chí bản gốc vi, trên thực tế, tên vilà "soạn thảo trực quan", và trình biên tập phi nhìn nó được xây dựng dựa trên ex .)


Để đơn giản hơn nữa (và để giảm nó thành một dòng), hãy sử dụng printfđể gửi các lệnh tới ex:

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


2

Một giải pháp khả thi là tạo ra một hàm để làm điều đó:

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

Đầu tiên chúng ta tạo một biến cục bộ l:ressẽ được sử dụng để đếm số lần xuất hiện của dòng.

Chúng tôi sử dụng globallệnh: mỗi lần dòng được khớp, l:resđược tăng lên.

Cuối cùng, nếu l:resvẫn là 0, điều đó có nghĩa là dòng không xuất hiện trong tệp vì vậy chúng tôi đi đến dòng cuối cùng nhờ Gvà chúng tôi tạo một dòng mới ođể chúng tôi viết dòng để thêm vào.

Lưu ý 1 Phương pháp tôi đã sử dụng để đặt giá trị l:reslà hơi nặng và có thể được thay thế bằng phương pháp được đề xuất bởi @Alex trong câu trả lời của anh ấy bằng một cái gì đó như:

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

Lưu ý 2 Ngoài ra để làm cho chức năng linh hoạt hơn, bạn có thể sử dụng các đối số:

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
  • Lưu ý mẹo với escape()việc thêm một \ký tự phía trước các ký tự có thể gây ra sự cố trong tìm kiếm.
  • Cũng lưu ý rằng bạn sẽ vẫn phải tự thoát \khi gọi hàm (Tôi không quản lý để \tự động thoát ):

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

2

Thử:

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

Lưu ý rằng :appendsẽ không hoạt động bên trong if endif-block với chế độ Ex (xem VimDoc ) vì vậy tôi phải đặt norm A...bên ngoài.


1

Tôi thường sử dụng:

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

1

Để đơn giản hóa và tránh sự hiện diện của nhiều người \, dòng sẽ được thêm vào export PATH=mybin:PATH.

Chiến lược chính: thay thế mybinvăn bản " không- " (tất cả tệp) bằng văn bản + mybin-path-định nghĩa:

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

hoặc với vết lõm mô phạm nhiều hơn :

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

Nếu chúng tôi có một trận đấu:

  1. &có toàn văn bashrc
  2. & không chứa /mybin:/

vì thế:

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

-cx                                   save and leave 

CẬP NHẬT : Cuối cùng, chúng ta có thể tạo một tập lệnh vim:

$ cat bashrcfix

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

chmod 755 và cài đặt nó. Sử dụng:bashrcfix


hãy cẩn thận: trong \vchế độ, =có nghĩa là tùy chọn


1

Hầu hết các câu trả lời có vẻ phức tạp về các lệnh shell cũ tốt:

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

Đây có thể dễ dàng là một hàm Bash:

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

addBashrcPath "~/.composer/vendor/bin"

EDIT : Mã thoát của grep rất quan trọng và trong trường hợp này cần phải đảo ngược việc sử dụng ! grep; grep -vsẽ không thoát như mong đợi trong tình huống này. Cảm ơn bạn @joeytwiddle cho tiền boa.


Tôi không nghĩ grep -vcung cấp cho bạn mã thoát bạn muốn. Nhưng ! grepnên làm điều đó.
joeytwiddle

Nếu đó là trường hợp thì bạn thậm chí không cần -vchỉ !.
Sukima

Chính xác. Bạn có thể chỉnh sửa câu trả lời của bạn để thực hiện điều chỉnh đó.
joeytwiddle

1
1. Bạn nên sử dụng -Fsao cho không grepdiễn giải các ký tự như các biểu thức thông thường và 2. Sử dụng -qthay vì chuyển hướng đến /dev/null. Xem bình luận trước đó của tôi về câu hỏi .
muru

Điểm tốt. Tò mò làm thế nào di động là -q-Fcác tùy chọn? Tôi nghĩ rằng >/dev/nullphổ biến hơn giữa các nền tảng khác nhau (sun vs hp vs Mac OS X vs Ubuntu vs FreeBSD vs,)
Sukima
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.