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
节中。
虽然理论上您可以完全在 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)
这使用了扩展的正则表达式语法-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)