web-dev-qa-db-ja.com

sed出力は、printfのフォーマットされた印刷のようにどのようにフォーマットできますか?

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セクションにあります。

7
Bram

これは、拡張正規表現構文-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
4
Peter.O

理論的には完全に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/.../.../')
4
mouviciel