Sedを使用したファイルテキストの追加

Sedを使用したファイルテキストの追加
#!/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.txtsearch_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

(これは他の答えといくつか重複しています。)

  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.txt1行だけ含めると、スクリプトは

    #!/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行に関連付けるには、必要な内容をより正確に説明してください。

  2. あなたは言う、

    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')

  3. まぁ、言っても

    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)を入力する必要があります。そして、単純化のためにコマンドを同じままにするには、最後のコマンドを次に変更することをお勧めします。$replacedreplaced=$(…)/sbin/iptables

    sed "s/$search_string/$replaced
    &/" result.txt
    

    代替文字列に使用することは、&「検索文字列(正規表現)で見つかったテキストをここに挿入する」という意味です。

  4. このsコマンドを使用すると、行全体を挿入できますが、実際にはこれは目的ではありません。aiおよびコマンド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.txtEnter

    ここにあります:

    • -np:またはコマンドでコマンドしない限り、出力を書き込まないでくださいr
    • /$search_string/{…}$search_string :()に一致する各行に対して、/sbin/iptables …次の操作を行います。
      • s/^/+/:行の先頭に+(create)を挿入します。+/sbin/iptables …これにより、行が検索文字列と一致するようにマークされます。 (私はこれについて戻ってきます。)
      • h+/sbin/iptables …パターンスペース()を予約済みスペースにコピーします。
      • r firewall.txtfirewall.txtファイルを読み、内容を書き込みます。
      • n:この行の処理を停止し、次の行を読みます。
    • それからその他ライン(いいえmatch $search_string) 次の操作を行います。
      • x:ホールド空間とパターン空間の内容を交換します。つまり、先ほど読んだ行いいえmatch $search_string)をストレージスペースにコピーし、以前に保存した行(スペースで+/sbin/iptables …もあります)をパターンスペースにコピーします。
      • s/^+//p:行が検索文字列と格納されている一致(つまり、報告済み)を含む行+/sbin/iptables …+残りの部分を削除して印刷します。それ以外の場合は何も印刷されません。
      • s/.*//:行を消去します(すべてを何でもないものに置き換えます)。もともとしたかったのですがdDelete) ここにありますが、現在の行の処理は終了します。
      • 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&/"

おすすめ記事