如何在本机 POSIX shell 脚本中乘以字符或字符串?

How can I multiply a character or string in native POSIX shell script?

这不是另一个问题的重复,原因有二。该问题没有指定答案必须是 POSIX。该问题的标记答案在 Dash shell 中 运行 不正确。 (我不知道如何判断答案是否为 POSIX 但它在最新版本的 Dash 上没有 运行。

澄清一下,我只想使用 POSIX shell 内置函数。我应该更清楚地说明这一点。据我所知,seq 是一个 GNU 实用程序,这意味着我必须生成一个外部程序。我不想生成任何外部程序。

我想知道在 shell 脚本中乘以字符串的最有效方法。例如,脚本将执行如下...

./multiplychar "*" "5"
*****
./multiplychar "*" "1"
*
./multiplychar "*" "0"

# It would not output anything

我好像找不到了,但是我很久以前就找到了bash的这个问题。然而,所有答案都使用了外部程序,如 Perl e.x。 perl -E "print '$' x " 或使用 bash 主义。

我想知道如何在 POSIX shell 中本地完成此操作。我正在使用破折号。如果有多种方式,以防与效率相关,我正在处理小于 100 的小数字。(这是一个严格基于文本的音量条通知的脚本。)

Shell: 破折号

OS:拱门Linux

这个简短的 bash 脚本可能会有用。它提供您想要的输出(使用 GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin18) 在 macOS 上测试)。我没有用 dash 测试它(不是真正使用它),但这似乎没有使用任何 bashisms.

#!/usr/bin/env bash

str=''

for i in `seq 1 ` ; do
    str="${str}"
done

echo "${str}"

如果 seq 不是 POSIX-compliant 或 dash-compliant,也许这可以解决问题(同样,仅使用 bash 进行测试):

#!/bin/sh

i=1
str=''

while [ "$i" -le "" ]
do
    i=`expr $i + 1`
    str="${str}"
done

echo "${str}"

示例:

$ ./test1.sh '*' 5
*****
$ ./test1.sh '*' 1
*
$ ./test1.sh '*' 0

*当然要加引号,但是数字不用加引号

一个简单的无循环 POSIX 函数,它构建一个足够长(125 个字符)的字符串,并使用 shell 的内置 printf 打印其中的一些:

multiplychar() { n="" 
                 n="$n$n$n$n$n"
                 n="$n$n$n$n$n"
                 n="$n$n$n$n$n"
                 printf %.""s\n "$n" ; }

测试运行:

$ multiplychar x 5
xxxxx
$ multiplychar x 0

$ multiplychar b 9
bbbbbbbbb

注意上面的代码实际上是一个乘法字符串函数:

$ multiplychar yow! 12
yow!yow!yow!

...它打印 12 个字符的重复字符串。如果字符串的第一个字符是所需的全部,则更改代码的第一行将 t运行cate 字符串:

multiplychar() { n="${1%%${1#?}}"
                 n="$n$n$n$n$n"
                 n="$n$n$n$n$n"
                 n="$n$n$n$n$n"
                 printf %.""s\n "$n" ; }

测试:

$ multiplychar yow! 12
yyyyyyyyyyyy

我找到的最短的almost-way就是这个,没有循环,没有seq:

已编辑 根据 MemReflect 的评论)

$ printf "%9s" ' ' | tr ' ' x 
xxxxxxxxx

所以你可以这样做:

#!/bin/sh
if [  -eq 0 ]; then
    exit
fi
printf "%s\n" ' ' | tr ' ' ""
$ ./multiplychar "*" "5"
*****
$ ./multiplychar "*" "1"
*
$ ./multiplychar "*" "0"
$

完全 POSIX 的方法是使用以下脚本。此脚本不创建任何外部进程,仅使用内置功能。

#!/bin/sh

_seq() (
    i=0 buf=
    while [ "$(( i += 1 ))" -le "" ]; do
        buf="$buf $i "
    done
    printf '%s' "$buf"
)

buf=
for i in $(_seq ""); do
    buf="$buf"
done
printf '%s\n' "$buf"

调用此脚本 ./multiplychar "*" 5 将打印 *****.

下面是这个脚本的工作原理,

_seq() 函数在子shell 中运行,因此它不会影响任何变量。调用 _seq 5 将输出 " 1 2 3 4 5 "for 循环中的空格无关紧要。

_seq() 函数和 main 函数中,输出都存储在一个名为 $buf 的变量中,因此我们只调用一次 printf

这应该是在您的 shell 上使用此功能的最有效和 POSIX 方式。