用另一个字符填充字符串中的尾随空格


12

我想输出hello world20个以上的字符。

printf "%-20s :\n\n" 'hello world!!'

# Actual output
hello world!!        :

# Wanted output
hello world!!========:

但是,我不想用空格来代替,而是用“ = ”来完成。我怎么做?

Answers:


9

更新了答案,成为更通用的解决方案。另请参阅下面的另一个答案,仅使用shell括号扩展和pritnf

$ str='Hello World!'
$ sed -r ':loop; s/ (=*):$/\1=:/; t loop' <<< "$(printf '%-20s:\n' "$str" )"
Hello World!========:

怎么运行的?

这会(=*):$/捕获一个空格,一个或多个空格,=然后:在输入末尾加一个冒号;我们将=一组作为一组匹配,\1并将其作为后向引用。

随着:loop我们定义了一个名为标签loopt loop它会跳到当该标签s/ (=*):$/\1=:/做了成功的替换;

在替换中\1=:,它将始终增加=s 的数量,并将冒号本身返回到字符串的末尾。


1
所以您必须根据输入的词数来调整标志?
user1686

@grawity我已经更新了对一般解决方案的回答。
αғsнιη

20
filler='===================='
string='foo'

printf '%s\n' "$string${filler:${#string}}"

foo=================

${#string}是值的长度$string,并且${filler:${#string}}$fillerfrom offset ${#string}开始的子字符串。

输出的总宽度将等于$filler或的最大宽度$string

填充字符串可以在具有的系统上jot使用来动态创建

filler=$( jot -s '' -c 16 '=' '=' )

=一行中有16 个)。GNU系统可以使用seq

filler=$( seq -s '=' 1 16 | tr -dc '=' )

其他系统可能会使用Perl或其他更快的方式动态创建字符串。


为什么不使用printf生成几乎在所有系统中都可用的过滤器以及带有类似shell的括号扩展bash/szh
αғsнιη

@sddgob如何使用printf+大括号扩展来实现bash
库萨兰达


17
printf "%.20s:\n\n" "$str========================="

%.20s字符串截断格式在哪里


2
这是恕我直言,比我的更好的解决方案。它只需要格式字符串的简短说明。
库萨兰达

12

一种方法是:

printf "====================:\r%s\n\n" 'hello world!!'

6
哈!这是一个聪明的把戏!但是,它实际上会打印====================\rhello world,如果OP需要存储它而不仅仅是将其打印到屏幕上,则可能会出现问题。
terdon

echo -e '=================\rHello World!!',但与@terdon指出的问题相同。
αғsнιη

1
@αғsнιη仅echo支持-e。 由于许多原因,printf几乎总是比更好echo
桂聪聪(SatōKatsura)

5

Perl方法:

$ perl -le '$k="hello world!!"; while(length($k)<20){$k.="=";} print "$k\n"'
hello world!!=======

或者,更好的是,@ SatoKatsura在评论中指出:

perl -le '$k = "hello world!!"; print $k, "=" x (20-length $k), "\n"'

如果需要支持UTF多字节字符,请使用:

PERL_UNICODE='AS' perl -le '$k = "hello world!!"; print $k, "=" x (20-length $k), "\n"'

外壳中的想法相同:

v='hello world!!'; while [ ${#v} -lt 20 ]; do v="$v""="; done; printf '%s\n\n' "$v"

您不需要循环:perl -le '$k = "hello world!!"; print $k, "=" x (20-length $k), "\n"'。但是,如果涉及多字节字符,则此方法(以及到目前为止发布的所有其他解决方案)会中断。
聪桂

@SatōKatsura哦,是的,这很干净!应该想到的,谢谢。是的,我在考虑为UTF多字节字符可能出现的故障添加免责声明,但认为在这种情况下这将是不必要的麻烦。
terdon

我认为perl6即使使用多字节字符,也可能有一种正确的方法。但另一方面,perl6它在很多方面都令人讨厌。
桂桂聪(SatōKatsura)

@SatōKatsura好,对于这种简单的事情,只需设置就足够了PERL_UNICODE='AS'。例如:printf '%s' nóóös | perl -nle 'print length($_)'打印8(“错误”),而printf '%s' nóóös | PERL_UNICODE='AS' perl -nle 'print length($_)'打印5(“正确”)。
terdon

5

另一种方法是只使用printf第一个命令,并生成字符填充图案的Shell Brace Expansion(你可以把结束与一些≥格式化要打印的区域{1..end}),并只得到它的每一个第一个字符%.1s=秒,然后只打印前20个字符长度那个区域%.20s。这是重复字符/单词而不是复制它们的更好方法。

printf '%.20s:\n' "$str$(printf '%.1s' ={1..20})"
Hello World!!=======:

说明:

通常以Brace Expansion表示{1..20}如果我们打印它们,则shell扩展如下。

printf '%s ' {1..20}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 

因此,在其上添加等号后={1..20},shell将如下扩展。

printf '%s ' ={1..20}
=1 =2 =3 =4 =5 =6 =7 =8 =9 =10 =11 =12 =13 =14 =15 =16 =17 =18 =19 =20 

而随着printf '%.1s'这实际上是手段printf '%WIDE.LENGTH',我们仅打印一个长度在以上这些默认的1 。因此只会产生=s,并且自身会重复20次。

现在,printf '%.20s:\n'我们仅打印20的长度,$str如果长度$str<20,则其余部分将从生成的=s中填充而不是空格。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.