この質問はレンダーテンプレートの使用に関するものです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"
私が理解したところ、このコードは次のことを行います。
${domain}
${1}
()のスクリプト引数に基づいて(まだ拡張されていない)文字列を変更しますexample.com
。メモリただし、nginx_app
ファイル自体は変更されません。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"
何が起こったのか:
シェルはコマンドラインを解析し、変数とリダイレクトを探します。
ファイル
/etc/nginx/sites-available/${domain}.conf
($domain
この変数の値に展開されています)がある場合は切り捨てられたり消去されたり、存在しない場合は空のファイルとして生成されます。ユーティリティは
sed
オペランド(対応する値に拡張されたがエスケープされているためまだ拡張されていません)とを使用して呼び出されます。シェルはまた、標準出力をリダイレクトしたいファイルに接続します。s/\${domain}/${1}/g
$1
${domain}
$
\
nginx_app
sed
オペランドが2つあるので、
sed
2番目のオペランドが読み取るファイルであるとします。最初のオペランドに編集コマンドを適用しながら、それを開き、1行ずつ読みます。すべての出力はリダイレクトされるファイルに入ります。
人々が言及した後sed -i
:
-i
指定されたファイルをsed
変更させるフラグsed
所定の位置につまり、標準出力には書き込まれませんが、変更結果は入力に使用されたのと同じファイルに反映されます。
内部的にはsed
書いて一時ファイル後で元のファイルをそのファイルに置き換えます。
この-i
フラグは、1つの引数(sed
GNUおよびこのユーティリティのいくつかの他の実装ではオプション、他のユーティリティでは必須)引数を使用します。
sed -i .bak '...some sed script...' filename
これにより、指定した文字列を新しいファイル名のサフィックスとして使用して元のファイルがバックアップされます。
私は通常、次のような理由で人々が-i
withを使用しないようにしようとします。sed
- 非標準拡張です。POSIX規格
sed
。 - 他のUnicesでは異なる動作をします。問題を見るsed -i(所定の位置で編集)を使用して移植性を達成するには?
sed
スクリプトに問題があるとデータが破損する可能性があるため、スクリプトのテストまたは開発に使用するのは危険です。
代わりに、私は人々に次のことをするように勧めます。
sed '...some sed script...' file >file-new && mv file-new file
&& mv
sed
...正しいテストを受けた後にのみ部品を追加してください。
&& mv
「前のコマンドがエラーなしで正常に終了した場合は、ファイル名を変更してください」を意味します。
答え2
この-i
フラグがないと、すべてのコマンドの結果がsed
標準出力に書き込まれます。
この例では、標準出力を別のファイル()にリダイレクトします/etc/nginx/sites-available/${domain}.conf
。
答え3
sed
ファイルに直接書き込むのではなく、出力をファイルにリダイレクトする理由を尋ねているようです。もしそうなら、いくつかの理由があります。
- 実際
-i
のパラメータでこれを行うことができますsed
。 - これは、他のプログラムと通信するプログラムを設計する一般的なUNIX哲学に従わないため、デフォルトの動作ではありません(https://en.wikipedia.org/wiki/Unix_philosophy)。
多くのUNIXシェルユーティリティの基本的な概念は、それらを互いにリンクすることです(foo | bar | baz
)。これにより、各フェーズ間でデータをディスクにバッファリングすることなく、データの複雑な処理を実行できます。