我正在尝试编写一个快速的 bash 函数,该函数README.md
用a 填充 a $1\n
,后跟下划线的长度$1
。
我在其他 stackexchange 问题中找到的代码表明,要打印字符<n>
时间,请使用
printf '=%.0s' {1..<n>}
事实上,这是可行的(显然<n>
用数字代替)。
为了创建我的README.md
,我认为该函数看起来像这样:
make_readme() {
echo "$1
$(printf '=%.0s' {1..${#1}})" > README.md
}
make_readme "Some project"
但是,这会生成一个包含以下文本的文件:
Some project
=
据我所知,${#1}
在 中$(...)
被替换为空字符串。我的猜测是命令替换有自己的参数范围,并且由于没有参数传递给替换,所以$1
被替换为空。
我最终找到了一些解决方法:
make_readme() {
underline="printf '=%.0s' {1..${#1}}"
echo "$1
$(eval "$underline")" > README.md
}
或者
make_readme() {
echo "$1" > README.md
printf '=%.0s' {1..${#1}} >> README.md
}
但似乎应该有一种方法可以在一行中完成此操作。
答案1
建议:
#!/bin/bash
make_readme () {
printf '%s\n%s\n' "$1" "$( eval "printf '=%.0s' {1..${#1}}" )"
}
make_readme 'Hello World!' >README.md
或者,如果调用外部实用程序可以,
#!/bin/bash
make_readme () {
# print $1, then replace all characters in it with = and print again
sed 'p; s/./=/g' <<<"$1"
}
make_readme 'Hello World!' >README.md
这两个都会生成一个名为README.md
包含的文件
Hello World!
============
答案2
我建议:
make_readme () {
printf '%s\n%s\n' "$1" "${1//?/=}"
}
make_readme 'Hello World!' >README.md
答案3
为您实际问题这是“给定一个字符串,产生一个等长string of = 我同意其他答案修改细绳使用 bash、zsh、tr、sed 等。
但为了你的陈述的问题这是“给定一个数字产生一个该长度的字符串”,你的方法不起作用的原因是 bash 进行了“参数扩展”,其中包括${#1}
后支撑扩张;看到手册或 Shell Expansions 下的信息。
有些方法你能创建一个仅给定长度的字符串:
- 使用你的
%.0s
技巧,但与程序seq
而不是大括号扩展(因为命令替换创建一个首先执行的子 shell,并进行参数扩展):
printf '%s\n' "$1"; printf '=%.0s' $( seq ${#1} ); printf '\n'
- 使用“可变宽度”格式
printf
创建填充,然后修改它:
# create a string of spaces equal to length of $1, then convert spaces to =
t=$(printf '%*s' ${#1} ''); printf '%s\n' "$1" "${t// /=}"
# create a string of zeros equal to length of $1, then convert zeros to =
t=$(printf '%0*d' ${#1} 0); printf '%s\n' "$1" "${t//0/=}"
- 使用 perl,这在当今的系统上很常见,但不是 POSIX:
printf '%s\n' "$1" "$( perl -e "print '='x${#1}" )"
# quoting $(perl...) isn't needed when we know (all) the chars are =
# but is good practice in general
# note I reverse the more common method of singlequoting a perl script
# with internal strings doublequoted, because I _want_ shell expansion
答案4
如果您不必使用bash
shell,请zsh
改为:
make_readme() printf '%s\n' $1 ${(l[$#1][=])}
左填充参数扩展标志在哪里(l[length][string])
(此处应用于根本没有参数)。
要考虑每个字符的显示宽度,因此它对于包含零宽度或双宽度字符的文本效果更好:
$ make_readme() printf '%s\n' $1 ${(l[$#1*3-${#${(ml:$#1*2:)1}}][=])}
$ make_readme $'Ste\u0301phane'
Stéphane
========
$ make_readme 'FOOBAR'
FOOBAR
============
(这些是 U+FF21..U+FF3A 双宽大写英文字母;您的浏览器可能不会将它们显示为完全双宽,但您的终端应该)。
${(ml:width:)1}
填充$1
到width
,考虑到每个字符的显示宽度,这允许我们$1
通过将 中的字符数$1
与填充到两倍字符数时的字符数进行比较来计算 的显示宽度。看获取字符串的显示宽度了解详情。