
私はCentOS Bash環境で作業しており、sed
プロのシステム管理者ではない人としてsed
少し「混乱する」ほど長いコマンドを持っており、少なくとも2年に1回、少なくとも長いコマンドとして使用します。
read new_email_address
sed -i 's/$to = ".*";$/$to = "'"$new_email_address"'";/' FILE
sed
コマンドを次のネストした擬似コードに分割したいと思います。
sed -i
'
s/
$to = ".*";$
/
$to = "'"$new_email_address"'";
/g
'
FILE_PATH
答え1
ここではこれを使いますperl
。-i
非標準オプションなので、一部のsed
実装ではそれをコピーしましたが、perl
移植可能ではありません。この方法を使用することもsed
コマンド注入の脆弱性です。内容が$new_email_address
最終的にsed
コードとして解釈されるためです(GNU言語には、そのプロンプトに入力しようとするなど、sed
任意のコマンドを実行できるコマンドがあります)。/;ereboot;#
read
IFS= read -r new_email_address
REPLACEMENT="$new_email_address" perl -pi -e '
s{
(\$to \s* = \s* ") .* (" \s* ; \s* )$
}{$1$ENV{REPLACEMENT}$2}gx
' FILE
存在するperl
s{...}{...}flags
extraを使用すると、一致するs/.../.../flags
ペアをより簡単に確認できます(そして一致する限り、内部使用も許可します){
。}
- この
x
フラグを使用すると、正規表現内にスペース(またはコメント)を追加して読みやすくすることができます(これらのスペースは正規表現の一部ではありませんが、\s*
任意の数のスペースと一致します)。 &
環境変数を使用して、、バックスラッシュ、または改行文字を含む文字列を渡す場合でも、置換に任意の文字列を安全に使用できます。/
-C
//-Mlocale
...-Mopen=locale
オプションを使用しない限りperl
、バイトレベルで作業するため、入力が.*
ロケールで有効なテキストを形成しない場合でも、一致は失敗しません。- 一部の
sed
実装とperl
は異なり、行の長さ(使用可能なメモリを除く)に制限はなく、NULバイトを含むか改行文字で終わらない入力をブロックしません。
交換部品にも空白を許可するには、e
交換部品をコードにするフラグを追加できますperl
。
REPLACEMENT="$new_email_address" perl -pi -e '
s{
(\$to \s* = \s* ") .* (" \s* ; \s* )$
}{
$1 . $ENV{REPLACEMENT} . $2
}gxe
' FILE
例えば。また、read
設定なし$IFS
となしを使用することは-r
ほとんど意味がありません。
答え2
もっと読みやすいかどうかはわかりませんが、sed
まずビルド式を使用してprintf
から次のように使用できますsed
。
sed_expr=$(printf 's/$to = ".*";$/$to = "%s";/' "$new_email_address")
sed -i "$sed_expr" FILE
私の考えでは、これはsedの全体的な機能と入力がどのように機能するかを理解するのが簡単です。
答え3
引用されたコマンドは次のとおりです。私は最近の回答に書きました。(追加-i
):
sed 's/$to = ".*";$/$to = "'"$new_email_address"'";/' file
これはsed
単一の編集コマンドで呼び出されます。式で使用されるコマンドは、置換を実行するコマンドsed
ですs
。つまり、正規表現と一致するものを別のものに置き換えます。
このコマンドの一般的な形式s
はですrange s/pattern/replacement/flags
。ここで扱うコマンドには表現はrange
ありません。s
みんな入力テキストの行)とnoですflags
。したがって、sed
通常のフォームに編集スクリプトがあります。
s/pattern/replacement/
コマンドが示すように、ビットpattern
は次のようになります。
$to = ".*";$
$to = "
このパターンは、次のリテラルテキストと一致します。何もない(長さに関係なくすべての文字のシーケンス)、その後にリテラルテキストが続きます";
。$
at the end は、最後の数字が行の最後";
に一致するように強制します。
そして私たちはそれを持っていますreplacement
。
シェル変数の値に依存するものに置き換えたいので、しばらく一重引用符で囲まれた文字列(つまり式)から外す必要がありますsed
。私たちはこれをした後
$to = "
交換中です。シェル変数の値はnew_email_address
挿入され、二重引用符で正しく引用されているため、シェルはそれをスペースに分割したり、その値に対してファイル名のグロービングを実行したりしません。
値を挿入したら、次のコマンドでコマンドreplacement
セクションを終了します。s
";
これはフィールドreplacement
全体で、$to = "
その後にいくつかの値(新しいEメールアドレス)が続きます";
。
したがって、命令の各ビットが実行し、何を意味するのかを分析し、明確に説明します。
コマンド構造sed
:
sed 's/$to = ".*";$/$to = "'"$new_email_address"'";/' file
s/ pattern / replacement /
sed
シェルで式を構成する文字列ビット:
sed 's/$to = ".*";$/$to = "'"$new_email_address"'";/' file
^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^ ^^^
single-quoted string double-quoted final single-quoted bit
string for shell
variable expansion
上記をもっと模式的に
sed 'something here'"$variable_value_here"'ending here' file
ビットsomething here
は二重引用符で終わり、ending here
ビットは二重引用符で始まります。
答え4
引用符を区切って保持する1つの方法は、複数の-e sedコードを使用して検索と置換を分離してsedコマンドを中断することです。
q=\"; # a double quote character
sed -i \
-e '/$to = ".*";$/c\' \
-e "\$to = $q$new_email_address$q;" \
FILE
sed -i \
-e '/$to = ".*";$/!b' \
-e "s//\$to = $q$new_email_address$q;/" \
FILE;