如何像 printf 的格式化打印一样格式化 sed 输出?

Bra*_*ram 7 sed text-processing columns

sed 可以用格式化为 printf 格式打印的字符串替换文本吗?

下面的 sed 命令用变量中指定的几个值替换以“$domain”的当前值开始的行。

/bin/sed  "s/\(^${domain} *${limittype} * ${limititem}.*\)/$EXPL#\1\n${domain} ${limittype} ${limititem} ${value}/" /etc/security/limits.conf
Run Code Online (Sandbox Code Playgroud)

然而,输出将不会正确对齐,因为域等值的长度不相同。

所以输出将类似于

#oracle   hard   nproc    131072
oracle hard nproc 666
Run Code Online (Sandbox Code Playgroud)

虽然有效,但很难阅读。我宁愿得到类似的东西

#oracle   hard   nproc    131072
oracle   hard   nproc    666
Run Code Online (Sandbox Code Playgroud)

我能得到的最好的输出是:

/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
Run Code Online (Sandbox Code Playgroud)

但我相信必须有一种更优雅的方式来做到这一点。

所述sed的一个衬里文件包含一些实例中使用指定数目的字符,例如

sed -e :a -e 's/^.\{1,78\}$/ &/;ta'  # set at 78 plus 1 space
Run Code Online (Sandbox Code Playgroud)

但这是在regexp节中而不是在replacement节中。

Gil*_*il' 6

虽然理论上您可以完全在 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
Run Code Online (Sandbox Code Playgroud)

\t如果您的 sed 不支持,请使用文字制表符\t。)

如果您事先不知道列宽,请尝试使用 BSDcolumn实用程序。它查看整个输入文件以确定容纳所有行长度的列宽。

</etc/security/limits.conf \
sed  "s/\(^${domain} *${limittype} * ${limititem}.*\)/$EXPL#\1 ${domain} ${limittype} ${limititem} ${value}/" |
column -t
Run Code Online (Sandbox Code Playgroud)

如果您的 sed 脚本重写了注释掉的行和未注释掉的行,或者如果您使用column,则需要进行一些后处理以将注释掉的行倾斜注释标记的宽度。

… | sed '/^#/ s/ //'
Run Code Online (Sandbox Code Playgroud)

您可以改用 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}
'
Run Code Online (Sandbox Code Playgroud)


Pet*_*r.O 4

这使用了扩展的正则表达式语法-r,它消除了很多混乱。另外,因为您已经知道一些字段值,所以实际上不需要反向引用它们,这再次减少了混乱(和开销)。

&是一个特殊的替换值:它保存整个匹配的模式。使用&, 再次减少混乱。由于它不是反向引用,因此开销显着减少。

我用过( +)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/" 
Run Code Online (Sandbox Code Playgroud)

输出

#oracle   hard   nproc    131072
oracle   hard   nproc    666
Run Code Online (Sandbox Code Playgroud)