GNU sed - 可変引数に基づいて既存のテンプレートの修正バージョンを作成する

GNU sed - 可変引数に基づいて既存のテンプレートの修正バージョンを作成する

この質問はレンダーテンプレートの使用に関するものですsed

テンプレートファイルがありますnginx_app

server {
    root ${drt}/${domain}/;
    server_name ${domain} www.${domain};
}

このファイルを別のスクリプトで使用します。

#!/bin/bash
domain="$1" && test -z ${domain} && return
sed "s/\${domain}/${1}/g" "nginx_app" > "/etc/nginx/sites-available/${domain}.conf"

もちろん、目的はexample.com.confそれに基づいてレンダリングテンプレートとして使用することです。nginx_app


上記のコードを考えてみましょう:

sed "s/\${domain}/${1}/g" "nginx_app" > "/etc/nginx/sites-available/${domain}.conf"

私が理解したところ、このコードは次のことを行います。

  1. ${domain}${1}()のスクリプト引数に基づいて(まだ拡張されていない)文字列を変更しますexample.comメモリただし、nginx_appファイル自体は変更されません。
  2. nginx_appレンダリングされたバージョンを/etc/nginx/sites-available/${domain}.conf

ここで正しいと仮定すると、コードを見ると、これらの作業は私にとって非常に直感的ではないと言うべきです。このコードの説明は正しいですか?

私の説明が十分に正確でない場合は訂正してください。

答え1

はい、本文の2番目の部分の理解は正確です。

sed他の多くのUnixツールと同様に、次のように動作すると言えます。フィルター。フィルタは入力を受け取り、修正して出力を生成します。多くの場合、フィルタリングを実行するユーティリティは、読み書き中かどうかわからない場合があります。文書。実際には、他のフィルタユーティリティから直接読み書きできます。これはユーティリティ自体に透過的で、シェルによって設定されます。

次の不要な使用法の事実を無視してくださいcat

cat <file | sed 's/^\([^=]*\)=\(.*\)$/#\1=\2 # old/' | tr -s ' ' >newfile

上記のユーティリティのどれもファイルの読み書きについては知りません。 catで読む標準入力ストリーム(シェルはのデータを含むように配列しますfile。)一度に1行ずつ出力を書き込みます。標準出力ストリーム(修正は必要ありません)。

sed次から読むそれ標準入力ストリーム(シェルが接続されている出力ストリームcat)は各入力行をいくつか変更し、その結果を標準出力ストリーム(接続tr)に書き込みます。

trまた、標準出力にのみ書き込みますが、シェルは出力がファイルに移動するようにリダイレクトを設定しますnewfile

プロセスの各段階で、各ユーティリティはパイプを介して必要な最小限のデータ(RAMに割り当てられたバッファ)のみを保存できます。これはnewfile、ファイルのデータを完全に読み取るfile前に結果が書き込まれ始めることができることを意味します(この例では)。


具体的な例:

sed "s/\${domain}/${1}/g" "nginx_app" > "/etc/nginx/sites-available/${domain}.conf"

何が起こったのか:

  1. シェルはコマンドラインを解析し、変数とリダイレクトを探します。

  2. ファイル/etc/nginx/sites-available/${domain}.conf$domainこの変数の値に展開されています)がある場合は切り捨てられたり消去されたり、存在しない場合は空のファイルとして生成されます。

  3. ユーティリティはsedオペランド(対応する値に拡張されたがエスケープされているためまだ拡張されていません)とを使用して呼び出されます。シェルはまた、標準出力をリダイレクトしたいファイルに接続します。s/\${domain}/${1}/g$1${domain}$\nginx_appsed

  4. オペランドが2つあるので、sed2番目のオペランドが読み取るファイルであるとします。最初のオペランドに編集コマンドを適用しながら、それを開き、1行ずつ読みます。

  5. すべての出力はリダイレクトされるファイルに入ります。


人々が言及した後sed -i

-i指定されたファイルをsed変更させるフラグsed所定の位置につまり、標準出力には書き込まれませんが、変更結果は入力に使用されたのと同じファイルに反映されます。

内部的にはsed書いて一時ファイル後で元のファイルをそのファイルに置き換えます。

この-iフラグは、1つの引数(sedGNUおよびこのユーティリティのいくつかの他の実装ではオプション、他のユーティリティでは必須)引数を使用します。

sed -i .bak '...some sed script...' filename

これにより、指定した文字列を新しいファイル名のサフィックスとして使用して元のファイルがバックアップされます。

私は通常、次のような理由で人々が-iwithを使用しないようにしようとします。sed

代わりに、私は人々に次のことをするように勧めます。

sed '...some sed script...' file >file-new && mv file-new file

&& mvsed...正しいテストを受けた後にのみ部品を追加してください。

&& mv「前のコマンドがエラーなしで正常に終了した場合は、ファイル名を変更してください」を意味します。

答え2

この-iフラグがないと、すべてのコマンドの結果がsed標準出力に書き込まれます。

この例では、標準出力を別のファイル()にリダイレクトします/etc/nginx/sites-available/${domain}.conf

答え3

sedファイルに直接書き込むのではなく、出力をファイルにリダイレクトする理由を尋ねているようです。もしそうなら、いくつかの理由があります。

  1. 実際-iのパラメータでこれを行うことができますsed
  2. これは、他のプログラムと通信するプログラムを設計する一般的なUNIX哲学に従わないため、デフォルトの動作ではありません(https://en.wikipedia.org/wiki/Unix_philosophy)。
    多くのUNIXシェルユーティリティの基本的な概念は、それらを互いにリンクすることです(foo | bar | baz)。これにより、各フェーズ間でデータをディスクにバッファリングすることなく、データの複雑な処理を実行できます。

関連情報