我将问题简化为(我认为)最简单的情况。假设我有一个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
将其格式字符串应用于输出中紧随其后的每个参数。它是一个bash
shell 内置函数,可用于将分隔符字符串应用于参数列表 - 某种程度。
例如:
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:}"
对于空格,您必须通过在IFS
before 之前设置变量来使用其他字段分隔符line
。