ファイルの最後にまだ行がない場合にのみ、行を追加する方法は?


10

行を追加してインプレースでファイルを編集したいのですが、まだ存在しない場合に限り、スクリプトを完全なものにします。

通常、私は次のようなことをします:

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

ansible(line+ insertafter=EOF+ regexp)を介してそれを行うことも可能ですが、それは別の話です。

vi / exでは、次のようなことができます。

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

しかし、理想的には同じ行を繰り返さずに、行が既に存在する(したがって何もしない)かどうかを確認するにはどうすればよいですか?

それともExエディタでそれを行う簡単な方法がありますか?


あなたはそれを外部委託できませんか?grep -Fq 'export PATH=~/.composer/vendor/bin:$PATH' ~/.bashrc || ex ...(またはcat、そのことについて)?
ムル

これはこのアプローチに似ていると思いますが、反対です(文字列が存在しない場合は、何かを行います)。
kenorb 2015

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

1
exportあるコマンドラインの残りの部分はシェル語、NOT割り当てているので、。したがって、(を使用しないexport)変数の割り当てとは異なり、二重引用符が必要です。そうしないと、空白で分割されますPATHにパスを正しく追加する方法も参照してください。
ワイルドカード

1
私は昨日探していた実際のリンクを見つけました(上記のリンクも良いですが)。 ローカル変数の割り当てには引用符が必要ですか?
ワイルドカード2016年

回答:


6

あなたがしたい場合は防弾を、あなたはおそらく上記の複雑なオプションよりも少しポータブル何かをしたいです。私はのPOSIX機能にex固執し、それを愚かな単純なものにします:行がそこにある場合は(行が何回あるかに関係なく)削除し、ファイルの最後に追加して、保存して終了します。

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

堅牢性を高めるために正規表現をアンカーしましたが、この正規表現を誤って一致させることはほとんど不可能だと思います。(使用したアンカー手段^$が一致する場合、正規表現にのみ一致するように全体行)。

+cmd構文はPOSIXでは必須ではなく、複数の-c引数を許可する一般的な機能でもないことに注意してください。


これを行うには、他にも多数の単純な方法があります。たとえば、ファイルの最後に行を追加してから、ファイルの最後の2行を外部UNIXフィルターで実行しますuniq

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

これは非常にクリーンでシンプルで、POSIXにも完全に準拠しています。外部テキストフィルタリング用のエスケープ機能ex、およびPOSIX指定のシェルユーティリティを使用します。uniq

一番下の行は、さex設計されたインプレースファイルの編集のために、それははるかに非対話形式であることを達成する最もポータブルな方法です。vi実際には、元のさえも古くなっています。名前viは「ビジュアルエディタ」の名前で、その上に構築された非ビジュアルエディタはでした ex。)


さらに単純にするために(そしてそれを1行に減らすために)、を使用printfしてコマンドをに送信しますex

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


2

可能な解決策は、それを行う関数を作成することです。

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

まずl:res、行の出現回数をカウントするために使用されるローカル変数を作成します。

globalコマンドを使用しl:resます。行が一致するたびに、インクリメントされます。

最後に、l:resまだ0の場合は、その行がファイルに表示されないことを意味するため、のおかげで最後の行に移動し、追加する行を書き込むG新しい行を作成しますo

注1の値を設定するために使用した方法l:resは少し重く、@ Alexが彼の回答で提案した方法に置き換えることができます。

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

注2また、関数をより柔軟にするために、引数を使用できます。

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
  • 検索の問題の原因となる可能性がある文字の前にescape()を追加するというトリックに注意してください\
  • また\、関数を呼び出すときに自分でをエスケープする必要があることにも注意してください(\自動でエスケープすることができませんでした)。

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

2

試してください:

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

Exモード(-VimDocを参照)では-blockの:append内部では機能しないことに注意してください。そのため、外部に配置する必要があります。if endifnorm A...


1

私は通常使用します:

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

1

多くの存在を単純化して回避するために、\追加される行は次のようになりますexport PATH=mybin:PATH

主な戦略:「非mybin」テキスト(すべてのファイル)をtext + mybin-path-definitionに置き換えます。

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

またはより教訓的なインデント

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

一致する場合:

  1. &bashrcおよびの全文があります
  2. & 含まない /mybin:/

そう:

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

-cx                                   save and leave 

UPDATE:最後に、vimスクリプトを作成できます。

$ cat bashrcfix

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

chmod 755をインストールします。使用法:bashrcfix


注意:\vモードで=は、オプションを意味します


1

これらの答えのほとんどは、古き良きシェルコマンドはどうでしょうか。

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

これは簡単にBash関数になる可能性があります。

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

addBashrcPath "~/.composer/vendor/bin"

編集:grepの終了コードは重要であり、この場合は逆に使用する必要があります! grepgrep -vこの状況では、期待どおりに終了しません。ヒントをありがとう@joeytwiddle


私はgrep -vあなたがあなたが望む終了コードを与えるとは思いません。しかし、それ! grepを行う必要があります。
joeytwiddle

その場合は、-vだけでも必要ありません!
スキマスイッチ

丁度。回答を編集して修正することができます。
joeytwiddle

1
1.あなたが使用する必要があります-Fようにgrepdosn'tが正規表現として文字を解釈し、2. -q代わりにリダイレクトの/dev/null以前の質問に対するコメントを参照してください。
muru

良い点。可搬性-q-Fオプションの違いを知りたいですか?>/dev/null異なるプラットフォーム間でより普遍的であると思いました(sun vs hp vs Mac OS X vs Ubuntu vs FreeBSD vs…)
Sukima
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.