将参数长度传递到 bash 命令替换中

将参数长度传递到 bash 命令替换中

我正在尝试编写一个快速的 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 下的信息

有些方法你创建一个仅给定长度的字符串:

  1. 使用你的%.0s技巧,但与程序 seq而不是大括号扩展(因为命令替换创建一个首先执行的子 shell,并进行参数扩展):
    printf '%s\n' "$1"; printf '=%.0s' $( seq ${#1} ); printf '\n'
  1. 使用“可变宽度”格式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/=}"
  1. 使用 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

如果您不必使用bashshell,请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}填充$1width,考虑到每个字符的显示宽度,这允许我们$1通过将 中的字符数$1与填充到两倍字符数时的字符数进行比较来计算 的显示宽度。看获取字符串的显示宽度了解详情。

相关内容