
#!/bin/bash
search_string="\/sbin\/iptables -A INPUT -p tcp --dport 12443 -j ACCEPT";
delimeters=$(cat /root/firewall/firewall.txt);
sed -i "s/$search_string/$delimeters$search_string/" /root/result.txt
変数に/root/firewall/firewall.txt
保存されている行の前にファイルの内容を追加したいです。/root/result.txt
search_string
上記の行を含めると、/root/firewall/firewall.txt
スクリプトが機能します。ただし、Firewall.txtに複数の行が含まれている場合、スクリプトは次のように中断されます。
sed: -e expression #1, char 64: unterminated `s' command
私の考えでは、改行文字が問題を引き起こしているようですが、正しくバックスラッシュできません。
search_string="\/sbin\/iptables -A INPUT -p tcp --dport 12443 -j ACCEPT";
delimeters=$(cat /root/firewall/firewall.txt);
replaced= "$delimeters" | sed -r 's/\\n/\\\\n/g'
sed -i "s/$search_string/$replaced$search_string/" /root/result.txt
この問題をどのように解決できますか?
答え1
(これは他の答えといくつか重複しています。)
少し混乱しています。あなたは言う、
ファイルの内容をファイル
firewall.txt
に追加したいと思います。result.txt
今後一行変数に保存しますsearch_string
。まず、問題の重要な部分ではない場合、フルパス名(
/root/…
)は問題を複雑にし、価値がなくなります。簡単なファイル名を使用してください。結局、ローカルディレクトリでデバッグしてほしいのですが、いいえルートとして実行します。第二に、何はいいくつかの例示的なデータを提供すると便利です。実際のファイルに実際にある2000行ではなく、数行です。 (やはり、テストファイルでこれをデバッグしているんですよね?) 例えば
result.txt
、One, two, /sbin/iptables -A INPUT -p tcp --dport 12443 -j ACCEPT Buckle my shoe.
そして
firewall.txt
包含Humpty Dumpty sat on a wall.
あなたは言う、
firewall.txt
1行だけ含めると、スクリプトは#!/bin/bash search_string="\/sbin\/iptables -A INPUT -p tcp --dport 12443 -j ACCEPT"; delimeters=$(cat /root/firewall/firewall.txt); sed -i "s/$search_string/$delimeters$search_string/" /root/result.txt
働く
(しかし、行の末尾にはセミコロンは必要ありませんが、「区切り記号」という単語は途中で「limit」という単語でスペルされます。)さて、上記の結果は次のとおりです。
One, two, Humpty Dumpty sat on a wall./sbin/iptables -A INPUT -p tcp --dport 12443 -j ACCEPT Buckle my shoe.
はいそれそれは本当にあなたが望むものですか? 「[a]ファイルに[テキスト]を追加すると言っても、ほとんどの人はそうは思いません。今後一行「特に、2行以上のテキストを挿入することについて話し始めるとき、特にそのように改行が続くはずです」と言うとき、そうです
firewall.txt
。One, two, Humpty Dumpty sat on a wall. /sbin/iptables -A INPUT -p tcp --dport 12443 -j ACCEPT Buckle my shoe.
ファイルの最後の行を
firewall.txt
この/sbin/iptables
行に関連付けるには、必要な内容をより正確に説明してください。あなたは言う、
search_string="\/sbin\/iptables -A INPUT -p tcp --dport 12443 -j ACCEPT"; delimeters=$(cat /root/firewall/firewall.txt); replaced= "$delimeters" | sed -r 's/\\n/\\\\n/g' sed -i "s/$search_string/$replaced$search_string/" /root/result.txt
まあ、それは無駄です。 3行目はこう答えます。
-bash: Humpty Dumpty sat on a wall.: command not found
おそらくあなたは
交換=$(エコ「$区切り記号」| sed -r 's/\\n/\\\\n/g')
?
まぁ、言っても
replaced=$(echo "$delimeters" | sed -r 's/\\n/\\\\n/g')
sed
通常、一度に1行ずつ実行し、改行文字を行の文字として扱わないため、役に立ちません(入力が複数行の値を持つシェル変数から来た場合も同様です. )。それは何をしますか?役に立たない使用cat
) はいreplaced=$(sed 's/$/\\/' firewall.txt) sed "s/$search_string/$replaced $search_string/" result.txt
を使用して、
sed 's/$/\\/'
各行の末尾にバックスラッシュを追加しますfirewall.txt
。コマンド置換が実行されると、最後の改行文字が削除されるため、その後に改行文字(Enter)を入力する必要があります。そして、単純化のためにコマンドを同じままにするには、最後のコマンドを次に変更することをお勧めします。$replaced
replaced=$(…)
/sbin/iptables
sed "s/$search_string/$replaced &/" result.txt
代替文字列に使用することは、
&
「検索文字列(正規表現)で見つかったテキストをここに挿入する」という意味です。この
s
コマンドを使用すると、行全体を挿入できますが、実際にはこれは目的ではありません。a
、i
およびコマンドc
は、コマンド文字列から1つ以上の行を挿入するために使用されます。ただし、挿入したテキストはファイルから取得したものなのでr
、アル字型ead)コマンド。最初のカットで、sed "/$search_string/r firewall.txt" result.txt
あなたが望むものはほとんどします。ほとんど。残念ながら、
firewall.txt
その行の後にファイルの内容を挿入します/sbin/iptables
。回避策(firewall.txt
行の前の内容を取得する方法)が見つかりましたが、/sbin/iptables
非常に複雑です。sed -n -e "/$search_string/{s/^/+/; h; r firewall.txt n}" -e 'x; s/^+//p; s/.*//; x; p' result.txt
明らかに、ファイル名を終わる区切り文字が
sed
認識されないため、と言うときはを入力する必要があります。;
r firewall.txt
Enterここにあります:
-n
p
:またはコマンドでコマンドしない限り、出力を書き込まないでくださいr
。/$search_string/{…}
$search_string
:()に一致する各行に対して、/sbin/iptables …
次の操作を行います。s/^/+/
:行の先頭に+
(create)を挿入します。+/sbin/iptables …
これにより、行が検索文字列と一致するようにマークされます。 (私はこれについて戻ってきます。)h
:+/sbin/iptables …
パターンスペース()を予約済みスペースにコピーします。r firewall.txt
:firewall.txt
ファイルを読み、内容を書き込みます。n
:この行の処理を停止し、次の行を読みます。
- それからその他ライン(いいえmatch
$search_string
) 次の操作を行います。x
:ホールド空間とパターン空間の内容を交換します。つまり、先ほど読んだ行いいえmatch$search_string
)をストレージスペースにコピーし、以前に保存した行(スペースで+/sbin/iptables …
もあります)をパターンスペースにコピーします。s/^+//p
:行が検索文字列と格納されている一致(つまり、報告済み)を含む行+/sbin/iptables …
、+
残りの部分を削除して印刷します。それ以外の場合は何も印刷されません。s/.*//
:行を消去します(すべてを何でもないものに置き換えます)。もともとしたかったのですがd
(Delete) ここにありますが、現在の行の処理は終了します。x
:ホールドスペースとパターンスペースの内容をやり直します。空白行をパターン空間から予約済み空間に移動し、配置したばかりのresult.txt
行を検索します。ついに…p
:で行を印刷しますresult.txt
。
要するに、
$search_string
一致する行(たとえば)を見つけたら、/sbin/iptables …
それを印刷せずに予約済みのスペースに保存し、ファイルを読み取って印刷しますfirewall.txt
。- 一致しない他のすべての行に対して、保存された行(存在する場合)を予約済みスペースから取得して印刷し、現在の行を印刷します。
ああ!最後の行で発生すると、
/sbin/iptables …
予約されたスペースには保持されますが、抽出をトリガーする一致しない後続の行がないため、失敗します。/sbin/iptables …
したがって、最後の行にダミーの行を追加してから戦略的に削除して、最後の行でこれが起こらないようにしましょう。echo >> result.txt sed -n -e "/$search_string/{s/^/+/; h; r firewall.txt n}" -e 'x; s/^+//p; $d; s/.*//; x; p' result.txt
これ
$d
により、最後の行が削除されます。 (私たちは$q
同じ効果を使用して得ることができます。)行が複数ある場合でも機能します
iptables
。しかし、はい、少し混乱しています。今、その答えはそれほど悪くないようです。sed "s/$search_string/$replacednewline&/"
答え2
一部の美容体操ではこれが可能かもしれませんが、sed
他のツールを使用します。 Perlを例に挙げてみましょう。
search_string="\/sbin\/iptables -A INPUT -p tcp --dport 12443 -j ACCEPT";
delimeters=$(cat /root/firewall/firewall.txt);
perl -i -pe "s/$search_string/$delimeters$search_string/" /root/result.txt
答え3
sedにはより多くのコマンドがあります。他のファイルを現在のストリームに読み込むs///
コマンドがあります。r
しかし、ファイルを読む後ろに現在行を配置する場合今後現在のラインなので少し調整が必要です。検索文字列でスラッシュをエスケープする必要はなく、sedで代替区切り文字を使用できます。
$ cat result.txt
foo
bar
/sbin/iptables -A INPUT -p tcp --dport 12443 -j ACCEPT
baz
$ cat firewall.txt
firewall line 1
firewall line 2
$ search_string="/sbin/iptables -A INPUT -p tcp --dport 12443 -j ACCEPT"
$ sed "\%${search_string}% {
# we have hit the search string:
x # move the current line to hold space
r firewall.txt # queue the file for reading
N # append the next line from results
# -> this triggers the actual file read and printing
s/\n// # the "x" command left behind a blank line so we remove it
H # append the current line to the hold space
g # then bring the hold space to the pattern space
}" result.txt
foo
bar
firewall line 1
firewall line 2
/sbin/iptables -A INPUT -p tcp --dport 12443 -j ACCEPT
baz
sed コマンドは次のように減らすことができます。
sed "\#${search_string}#{x;r firewall.txt
N;s/\n//;H;g}" result.txt
GNU sedはファイル名の後に改行文字が必要なようです。
答え4
sed '/\-A INPUT -s 192.168.0.0\/24 -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT/a CLIENTSCRIPT2="hello.sh"' file.txt
この場合、-A INPUT ...etcの下のfile.txtに変数CLIENTSCRIPT2 = "hello.sh"'を追加しました。構文でバックスラッシュがエスケープされることに注意してください。