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 oneliners ドキュメント指定された数の文字を使用するいくつかの例が含まれています。
sed -e :a -e 's/^.\{1,78\}$/ &/;ta' # set at 78 plus 1 space
しかし、これはregexp
章ではなく章にありますreplacement
。
答え1
理論的には、この作業はsedで完全に実行できますが(Turingが完了したため)、作業に適したツールではありません。
簡単な方法は、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
\t
(Sedがそれをサポートしていない場合は、リテラルタブを使用してください\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}
'
答え2
-r
これは多くの混乱を排除する拡張正規表現構文を使用します。また、いくつかのフィールド値を既に知っているので、実際には逆参照する必要がないため、混乱やオーバーヘッドが減ります。
&
特別な代替値です。一致するパターン全体を保存します。&
混乱を減らすには、をもう一度使用してください。逆参照ではないため、オーバーヘッドが大幅に削減されます。
私は入力フィールドの間に少なくとも1つのスペースがあると仮定して( +)
vs ( *)
..を使用しました。事実ではないという +
事実に置き換えてください。*
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
答え3
sed出力フォーマットを指定するには、printfを使用してください。
printf "%5s %12s %4s\n" $(sed 's/.../.../')