假设我有这个:
str="@test/string"
echo $str
@test/string
echo ${str#@}
test/string
按预期工作,但是
echo ${str//\//-}
ksh: ${str//\//-}: bad substitution
失败。 (预期@test-string)
像这样替换/替换字符的正确方法是什么?
echo $KSH_VERSION
KSH version @(#)PD KSH v5.2.14 99/07/13.2
答案1
Yes${var//pattern/replacement}
是一个 ksh93 操作符,而 pdksh 旨在作为原始 ksh 的克隆,其最后一个版本是 ksh88i1。 pdksh 作为一个项目已经停止,但它仍然存在,因为它是sh
少数 BSD 的一部分,包括 OpenBSD 和 MirBSD。 MirBSD sh/ksh 也称为 mksh,也作为便携式 shell 维护,并且在许多 Linux 发行版中可用(甚至在 Android 上使用sh
)。它确实在 2008 年的 R33 版本中添加了 ksh93 运算符。
POSIXly,要将变量中的一个字符替换为另一个字符,您可以使用tr
ansliterator 实用程序,但您需要在其 stdin 上提供变量的内容并从其 stdout 获取结果:
newstr=$(printf %s "$str" | tr / -; echo .)
newstr=${newstr%.}
(添加的内容.\n
是为了解决命令替换会删除尾随换行符的事实)。
您还可以使用 split+glob 运算符来避免运行单独的命令:
IFS=/ # split on /
set -o noglob # disable the glob part
set -- $str'' # split+glob by leaving $str unquoted
IFS=. # join on . in "$*"
newstr="$*"
1 虽然 ksh93 是一个不完全向后兼容的重写,但具有许多新功能,其中许多仍处于实验阶段,并且在其代码在 2000 年代作为开源发布之前很少使用
答案2
shellpdksh
是 OpenBSD 等新用户的默认 shell,没有您提到的非标准参数替换。
要将某些模式的所有非重叠匹配替换为某个新字符串,您可以使用sed
:
str=$( printf '%s\n' "$str" | sed 's/PATTERN/REPLACEMENT/g' )
请注意,这用作PATTERN
POSIX 基本正则表达式,REPLACEMENT
必须转义&
,\1
以及将以特殊方式解释的其他字符串sed
,并且命令替换会从字符串末尾删除所有尾随换行符。
例子:
$ str=@title/section1/section2
$ str=$( printf '%s\n' "$str" | sed 's/\//-/g' )
$ printf '%s\n' "$str"
@title-section1-section2
在这种情况下,当仅替换单个字符时,可以将替换替换sed
为y/\//-/
,或将整个sed
命令替换为tr
命令tr / -
。
您还可以选择编写 shell 循环:
while true; do
case $str in
*PATTERN*)
str=${str%%PATTERN*}REPLACEMENT${str#*PATTERN}
;;
*)
break
esac
done
在此代码中,PATTERN
是一个 shell 模式(“文件名通配模式”)。该代码重复使用替换字符串替换字符串中模式的第一个匹配项,直到不再有匹配项。由于循环的存在,无法保证后续迭代不会在先前插入的替换字符串中执行替换。
例子:
$ str=@title/section1/section2
$ while true; do case $str in (*/*) str=${str%%/*}-${str#*/} ;; (*) break; esac; done
$ printf '%s\n' "$str"
@title-section1-section2
答案3
肯定是更好的方法,但是:
$(echo "$str" | tr '/' '-')