如何在 bash 中使用多字符分隔符进行数组扩展?

如何在 bash 中使用多字符分隔符进行数组扩展?

我将问题简化为(我认为)最简单的情况。假设我有一个myscript.sh包含以下内容的脚本:

#!/bin/bash
IFS='%20'
echo "$*"

如果我按如下方式运行命令,输出将如下所示:

me@myhost ~ $ ./myscript.sh fee fi fo fum
fee%fi%fo%fum

这是预期的行为,如bash手册页中所述:

   *      Expands  to  the positional parameters, starting from one.  When
          the expansion occurs within double quotes, it expands to a  sin-
          gle word with the value of each parameter separated by the first
          character of the IFS special variable.  That is, "$*" is equiva-
          lent to "$1c$2c...", where c is the first character of the value
          of the IFS variable.  If IFS is unset, the parameters are  sepa-
          rated  by  spaces.   If  IFS  is null, the parameters are joined
          without intervening separators. 

但是,我想要得到的是输出:

fee%20fi%20fo%20fum

因此使用多个字符分隔符字段而不是单个字符。

有没有一种方法可以做到这一点bash


更新:

基于下面 mikeserv 的数据以及以下位置的文章为什么 printf 比 echo 更好?,我最终执行了以下操作(再次简化为最简单的情况,如上例所示):

#!/bin/bash
word="$1"
shift
if [ "$#" -gt 0 ] ; then
    word="$word$(printf '%%20%s' "$@")"
fi
printf '%s\n' "$word"
unset word

答案1

printf将其格式字符串应用于输出中紧随其后的每个参数。它是一个bashshell 内置函数,可用于将分隔符字符串应用于参数列表 - 某种程度。

例如:

printf %s:delimit: arg1 arg2 arg3

arg1:delimit:arg2:delimit:arg3:delimit:

问题是,printf停止在其参数末尾应用其格式字符串,因此最后一个参数会附加一个分隔符。在某些情况下可以这样处理:

printf %b:delimit: \\0150 \\0145 \\0171\\c

h:delimit:e:delimit:y

printf将 C 和八进制转义符解释为%b具有某种格式的 ytes,并且还具有%b\c在某个点输出其输出的格式,这就是为什么printf上面的 y 后面不跟有:delimit:字符串,因为其格式字符串会以其他方式指示。

所以如果你想从字面上解释每个参数没有尾随分隔符,那么您必须解决参数列表本身的问题:

set -- arg1 arg2 arg3
for arg do shift
    set -- "$@" :delimit: "$arg"
done; shift
printf %s "$@"

arg1:delimit:arg2:delimit:arg3

答案2

在 中zsh,您可以使用j:string: 参数 扩展标志:

set -- fee fi fo fum
delims=%20
print -rl ${(j:$delims:)@}

答案3

如果您使用bash(或其他启用了变量扩展的 shell)并且参数内部没有空格,您可以执行以下操作:

#!/bin/bash
line=$*
echo "${line// /:delimiter:}"

对于空格,您必须通过在IFSbefore 之前设置变量来使用其他字段分隔符line

相关内容