如何在本机 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 方式。
这不是另一个问题的重复,原因有二。该问题没有指定答案必须是 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 方式。