まだ存在しない場合にのみ、ファイルに行を追加する


157

構成ファイルの最後に次の行を追加する必要があります。

include "/configs/projectname.conf"

というファイルに lighttpd.conf

私はsedこれを行うために使用することを検討していますが、方法を理解できません。

行がまだ存在しない場合にのみ挿入するにはどうすればよいですか?


iniファイルを編集しようとしている場合は、ツールcrudiniが適切なオプションである可能性があります(ただしlighthttpdにはまだ対応していません)
rubo77

回答:


292

シンプルにしてください:)

grep + echoで十分です:

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

編集:@cerinおよび@ thijs-woutersの提案を組み込みました


2
私は抑制出力にはgrepに-qスイッチを追加します。 grep -vq ...
デイブカービー

1
参考までに、-vと&&を使用しても効果はありません。|| -vなしで機能します。
bPizzi 2010

3
これは非常に単純な線に対してのみ機能します。そうでない場合、grepは行内のほとんどの非英字をパターンとして解釈し、ファイル内の行を検出しなくなります。
セリン14

2
美しいソリューション。もちろん、これはより複雑な式をトリガーする場合にも機能します。Mineはを使用しechocat複数行のヒアドキュメントを構成ファイルにトリガーします。
Eric L.

2
追加-sだけでその行で新しいファイルを作成し、ファイルが存在しない場合にエラーを無視します。
フランク

78

これは使用して、きれいな読み取りおよび再利用可能な解決策になるgrepecho、それはまだ存在しない場合にのみファイルに行を追加します:

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

ライン全体を一致させる必要がある場合 grep -xqF

追加-sだけでその行で新しいファイルを作成し、ファイルが存在しない場合にエラーを無視します。


5
root権限が必要なファイルの場合:sudo grep -qF "$LINE" "$FILE" || echo "$LINE" | sudo tee -a "$FILE"
nebffa

行がで始まる場合、これは実際には機能しません-
ハイパーノット2018

@zsero:良い点!--grepコマンドに追加したので、ダッシュで始まる$ LINEがオプションとして解釈されなくなりました。
rubo77 2018

13

ここにsedバージョンがあります:

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

文字列が変数にある場合:

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

部分的な文字列を完全な/更新された設定ファイルエントリで置き換えるコマンド、または必要に応じて行を追加するコマンドの場合: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

いいですね、+ 1に大いに役立ちました。sedの表現について説明してください。
Rahul

このソリューションの注釈付きの説明をご覧ください。私はsed何年も使用してきましたが、ほとんどがsコマンドだけです。holdそしてpatternスペーススワップは私を超えています。
通常、2016年

11

保護されたファイルに書き込む場合、sudoを実行できないため、@ drAlberTと@ rubo77の回答が機能しない場合があります>>同様に、単純な溶液、次いで、使用することであろうtee --append(MacOSの上に、または、tee -a):

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

6

1日は、他の誰かが、場合持っている「レガシーコード」として、このコードに対処するために、あなたのような、あまり平凡なコードを書く場合、その人は感謝するだろうということ

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

1
シェルがわからない場合は、Windowsにアクセスして管理してください。&&と||を使用するソリューション 通常のシェル構文であり、有能な管理者が理解する必要があります。難解なことは何もありません。
Graham Nicholls、2018年

3
グラハムさん、コメントありがとうございます!はい、それは通常のシェル構文です。そして、はい、有能な管理者はそれを理解する必要があります。ただし、シェル内の式評価アルゴリズムの副作用に基づいて機能します。だからあなたはそれを好きなように呼ぶことができますが、単純なものを除いて-それは私の元のポイントでした。
Marcelo Ventura


6

別のsedソリューションは、常に最後の行に追加し、既存のものを削除することです。

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

「適切にエスケープする」とは、エントリに一致する正規表現を配置すること、つまり実際のエントリからすべての正規表現コントロールをエスケープすること、つまり^ $ / *?+()の前にバックスラッシュを配置することを意味します。

これはあなたのファイルの最後の行で失敗するかもしれません、またはぶら下がっている改行がない場合、私にはわかりませんが、それはいくつかの気の利いた分岐で対処できます...


1
素敵なワンライナー、短くて読みやすい。etc / hostsの更新に最適:sed -i.bak -e '$a\' -e "$NEW_IP\t\t$HOST.domain\t$HOST" -e "/.*$HOST/d" /etc/hosts
Noam Manos

小さいバージョン:sed -i -e '/<entry>/d; $a <entry>'
ジェローム・Pouiller

@Jezzエントリがすでにファイルの最後にある場合、これは失敗すると思います。削除がたまたま最後の行にある場合、dコマンドはsedプログラムを再起動して、aペンドをスキップするためです。
Robin479

@ Robin479くそー、aペンドはdeleteの前に実行する必要があります:sed -i -e '$a<entry>' -e '/<entry>/d'。元の答えとほぼ同じです。
ジェローム・Pouiller

3

awkを使用する

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

それは「ファイルファイル」ですか、それとも単に「ファイル」ですか?
webdevguy 14

これfile fileは、同じファイルに対して2つのパスを作成するためです。NR==FNR最初のパスではtrueですが、2番目のパスではありません。これは一般的なAwkイディオムです。
tripleee 2017年

1

grepを使用した答えは間違っています。行全体を一致させるには-xオプションを追加する必要があります。そうしない#text to addと、正確に追加しようとすると、行が一致しtext to addます。

したがって、正しい解決策は次のようなものです。

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

1

sedの使用:行末に挿入されます。もちろん、通常どおり変数を渡すこともできます。

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

ワンライナーsedの使用

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

エコーの使用はルートの下では機能しないかもしれませんが、このように機能します。ただし、パスワードを要求する可能性があるため、自動化しようとしている場合は自動化できません。

特定のユーザーのルートから編集しようとしたときに問題が発生しました。$username以前を追加するだけで解決しました。

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

Stackoverflowへようこそ!回答を投稿する前に質問をよく読んでください-OPはsedを使用して挿入する方法を尋ねました
Markoorn

-1

書き込み権限が制限されているファイルを編集する必要があったため、必要に応じてsudo。ghostdog74の答えから作業し、一時ファイルを使用します:

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

これは正しくありません。config行がない場合、ファイルから他の行が失われます。
tripleee 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.