Sedは、printfのフォーマットされた印刷のようなフォーマットの文字列でテキストを置き換えることができますか?
次のsedコマンドは、「$ domain」の現在の値で始まる行を、変数で指定されたいくつかの値に置き換えます。
/bin/sed "s/\(^${domain} *${limittype} * ${limititem}.*\)/$EXPL#\1\n${domain} ${limittype} ${limititem} ${value}/" /etc/security/limits.conf
ただし、ドメインなどの値の長さが同じでないため、出力は適切に整列されません。
したがって、出力は次のようになります
#Oracle hard nproc 131072
Oracle hard nproc 666
有効ですが、読みにくいです。私は次のようなものを得たいと思います
#Oracle hard nproc 131072
Oracle hard nproc 666
望ましい出力を得るために私ができる最高のものは:
/bin/sed "s/\(^${domain}\)\( *\)\(${limittype}\)\( *\)\(${limititem}\)\( *\)\(.*\)/$EXPL#\1\2\3\4\5\6\7\n${domain}\2${limittype}\4${limititem}\6${value}/" /etc/security/limits.conf
しかし、これを行うにはよりエレガントな方法が必要だと思います。
sed one liners document には、指定された文字数を使用するいくつかの例が含まれています。
sed -e :a -e 's/^.\{1,78\}$/ &/;ta' # set at 78 plus 1 space
ただし、これはregexp
セクションではなくreplacement
セクションにあります。
これは、拡張正規表現構文-r
を使用して、混乱を解消します。また、すでにいくつかのフィールド値を知っているので、実際にそれらを後方参照する必要はなく、再び混乱(およびオーバーヘッド)を減らします。
&
は特別な置換値です。一致したパターン全体を保持します。 &
を使用すると、混乱が減ります。後方参照ではないため、オーバーヘッドが大幅に少なくなります。
( +)
と( *)
を使用しました。 +
は、入力フィールドの間に少なくとも1つのスペースがあることを前提としています。 *
に変更してください。そうではありません。
EXPL=
dom=Oracle
typ=hard
itm=nproc
val=666
echo "Oracle hard nproc 131072" |
sed -r "s/^$dom( +)$typ( +)$itm( +).*/$EXPL#&\n$dom\1$typ\2$itm\3$val/"
出力
#Oracle hard nproc 131072
Oracle hard nproc 666
理論的には完全にsedでこれを行うことができますが(これはチューリング完全であるため)、これはジョブに適したツールではありません。
簡単な方法は、sedにタブを挿入し、それらをスペースに後処理することです。すべての列の位置を特定できる場合は、sed出力を expand
にパイプします。
</etc/security/limits.conf \
sed "s/\(^${domain} *${limittype} * ${limititem}.*\)/$EXPL#\1\n${domain}\t${limittype}\t${limititem}\t${value}/" |
expand -t 10,17,26
(sedが\t
をサポートしていない場合は、\t
の代わりにリテラルタブ文字を使用してください。)
事前に列幅がわからない場合は、BSD column
ユーティリティを試してください。入力ファイル全体を調べて、すべての行の長さに対応する列幅を決定します。
</etc/security/limits.conf \
sed "s/\(^${domain} *${limittype} * ${limititem}.*\)/$EXPL#\1 ${domain} ${limittype} ${limititem} ${value}/" |
column -t
Sedスクリプトがコメント化された行とコメント化されていない行の両方を書き換える場合、またはcolumn
を使用する場合は、コメント化された行をコメントマーカー。
… | sed '/^#/ s/ //'
代わりにawkを使用できます。 printf
関数があります。追加のボーナスとして、検索対象の列コンテンツの.
や*
などの特殊文字を保護する簡単な方法があります。
</etc/security/limits.conf awk -v domain="$domain" -v limittype="$limittype" -v limititem="$limititem" -v value="$value" '
$1 == domain && $2 == limittype && $3 == limititem {
printf "#%-9s %-8s %-9s %s\n%-9s %-8s %-9s %s\n", $1, $2, $3, $4, $1, $2, $3, value; next
}
1 {print}
'
Printfを使用して、sed出力をフォーマットします。
printf "%5s %12s %4s\n" $(sed 's/.../.../')