次の行を追加するために、次のsed cliをビルドします。
force_https_protocol=PROTOCOL_TLSv1_2
次の行の後:
[security]
sed cli:
sed -i '/\[security\]/a force_https_protocol=PROTOCOL_TLSv1_2' /etc/ambari-agent/conf/ambari-agent.ini
しかし、問題は、その行がforce_https_protocol=PROTOCOL_TLSv1_2
すでに[security]
行がすでに存在する場合に行の追加を無視するように sed 構文を変更するにはどうすればよいでしょうか?
期待される出力
[security]
force_https_protocol=PROTOCOL_TLSv1_2
keysdir=/var/lib/ambari-agent/keys
server_crt=ca.crt
passphrase_env_var_name=AMBARI_PASSPHRASE
間違ったファイル:
[security]
force_https_protocol=PROTOCOL_TLSv1_2
force_https_protocol=PROTOCOL_TLSv1_2
keysdir=/var/lib/ambari-agent/keys
server_crt=ca.crt
passphrase_env_var_name=AMBARI_PASSPHRASE
答え1
ファイル内のすべての「force_https_protocol=PROTOCOL_TLSv1_2」が[security]タグ内にあり、他の場所には現れないと仮定します。
sed -e '/^force_https_protocol=PROTOCOL_TLSv1_2$/d'\
-e '/\[security\]/a force_https_protocol=PROTOCOL_TLSv1_2' file
アイデアは、ファイル内の「force_https_protocol=PROTOCOL_TLSv1_2」文字列のみを含むすべての行を削除することです。
説明
/^force_https_protocol=PROTOCOL_TLSv1_2$/d'
「force_https_protocol=PROTOCOL_TLSv1_2」文字列を含むすべての行を削除します。
テスト
$ cat file
[security]
force_https_protocol=PROTOCOL_TLSv1_2
keysdir=/var/lib/ambari-agent/keys
server_crt=ca.crt
passphrase_env_var_name=AMBARI_PASSPHRASE
[security]
keysdir=/var/lib/ambari-agent/keys
server_crt=ca.crt
passphrase_env_var_name=AMBARI_PASSPHRASE
$ sed -e '/^force_https_protocol=PROTOCOL_TLSv1_2$/d'\
-e '/\[security\]/a force_https_protocol=PROTOCOL_TLSv1_2' file
[security]
force_https_protocol=PROTOCOL_TLSv1_2
keysdir=/var/lib/ambari-agent/keys
server_crt=ca.crt
passphrase_env_var_name=AMBARI_PASSPHRASE
[security]
force_https_protocol=PROTOCOL_TLSv1_2
keysdir=/var/lib/ambari-agent/keys
server_crt=ca.crt
passphrase_env_var_name=AMBARI_PASSPHRASE
答え2
1. AWKの使用
より一般的な問題に対する解決策としては、弦ラベル付きテキストブロック(つまり、ファイル内の特定のラベルに続き、次のラベルまたはファイルの先頭に続くテキスト行)にのみ適用されます。弦まだ存在しません。
簡単な方法は、ファイルを遡って、最後に遭遇した時刻を追跡することです。弦特定のラベルに遭遇するたびに(ラベル自体を印刷する直前に)それを印刷しますが、まだそれを見たことがない場合のみです(弦) に遭遇したことを忘れてしまう (弦) ラベルに遭遇するたびに、結果を反転します。そして、もちろん、最後のステップとして結果を反転します。
tac file | awk '
/^force_https_protocol=PROTOCOL_TLSv1_2$/ {
seen = 1
}
/^\[security\]$/ {
if ( ! seen ) {
print "force_https_protocol=PROTOCOL_TLSv1_2"
}
}
/^\[[^]]*\]$/ {
seen = 0
}
1' | tac
tac
、含まれるGNU コアユーティリティは、ファイルを行ごとに連結して反転します。他の/標準ツールでファイルを反転する方法は、U&LのいくつかのQ/Aで説明されています(たとえば、コマンド sed '1!G;h;$!d' はどのようにしてファイルの内容を反転するのでしょうか?そして逆グレッピング)。
これは、次のテキスト スニペットのforce_https_protocol=PROTOCOL_TLSv1_2
最初の後には挿入されません。[security]
[security]
keysdir=/var/lib/ambari-agent/keys
force_https_protocol=PROTOCOL_TLSv1_2
passphrase_env_var_name=AMBARI_PASSPHRASE
[security]
...
単に挿入する弦ラベルが出現するたびに、弦すでに存在する場合、同じアプローチで次の結果が生じる可能性があります。
tac file | awk '
/^force_https_protocol=PROTOCOL_TLSv1_2$/ {
seen = NR
}
/^\[security\]$/ {
if ( ( NR == 1 ) || ! ( NR == seen + 1 ) ) {
print "force_https_protocol=PROTOCOL_TLSv1_2"
}
}
1' | tac
(これ意思force_https_protocol=PROTOCOL_TLSv1_2
上記のテキストサンプルの後に挿入します[security]
。
2. sedの使用
sed
サイクルのバリエーションを使用できます(N;P;D;
これは、U&L の他の Q/A で豊富にカバーされています。たとえば、次のようになります)。sed を使用して複数行の文字列を置き換えるにはどうすればよいですか?またはsed を使用してパターンの後の次の行を編集するにはどうすればよいでしょうか?)。
これにより、前者がまだ存在しない場合にのみ、のみforce_https_protocol=PROTOCOL_TLSv1_2
で構成された行の後に行が挿入されます。[security]
sed '
$! {
N
P
/^\[security\]\n/ {
/\nforce_https_protocol=PROTOCOL_TLSv1_2$/ b b
i\
force_https_protocol=PROTOCOL_TLSv1_2
}
:b
D
}
s/^\[security\]$/&\
force_https_protocol=PROTOCOL_TLSv1_2/'
このスクリプト:
- 最後の行 ( ) を除く各行に対して、
$!
改行とそれに続く次の行をパターン スペース (N
) (現在の行がすでに含まれています) に追加します。 - パターンスペースの最初の行 (
P
) を出力します。その行が[security]
... の場合- ...次の行は
force_https_protocol=PROTOCOL_TLSv1_2
、パターンスペースから最初の行を削除し、新しいサイクル (b b
、:b D
) を開始します。 - それ以外の場合は、パターンスペースから最初の行を削除して新しいサイクルを開始する前に、
force_https_protocol=PROTOCOL_TLSv1_2
標準出力()に印刷します。i\
D
- ...次の行は
- 最後の行が の場合
[security]
、 はそれを 自身に続いて改行と に置き換え、force_https_protocol=PROTOCOL_TLSv1_2
結果を出力します (暗黙の を使用してp
)。